[Tex/LaTex] Proper use of \mathchoice

math-modespacing

I am trying to learn how to use \mathchoice.

Before the solution was posted for Non-invasive replacement for \fbox?, I attempted to use mathchoice to adjust the size of the parameter before measuring its height, depth and width. To simply things, I first defined:

\newcommand{\SetHeightDepthWidth}[1]{%          
    \settoheight{\fillbox@height}{#1}%   
    \settodepth{\fillbox@depth}{#1}%     
    \settowidth{\fillbox@width}{#1}%     
}%

Then adjusted the beginning of the \fillbox macro as:

\newcommand{\fillbox}[1]{%
  \ifmmode%                                             
    \mathchoice%                                        
        {\SetHeightDepthWidth{$\displaystyle#1$}}%      
        {\SetHeightDepthWidth{$\textstyle#1$}}%         
        {\SetHeightDepthWidth{$\scriptstyle#1$}}%       
        {\SetHeightDepthWidth{$\scriptscriptstyle#1$}}% 
  \else%                                                
    \SetHeightDepthWidth{#1}%                           
  \fi%                                                  

Before these changes, the output was:

enter image description here

But with the above changes I get:

enter image description here

So, what happened? To me it appears to be some problem related to the grouping due to the extra brace groups required to pass in the four parameters to \mathchoice, but don't know how to fix it. Does \mathchoice behave differently than many of the other types of conditional macros such as \iftoggle{condition}{code if true}{code if false} from the etoolbox package?

Code:

The new code is marked and the old code is left commented to simplify comparison.

\documentclass{article}
\usepackage{tikz}

\makeatletter
  \newlength\fillbox@height%
  \newlength\fillbox@depth%
  \newlength\fillbox@width%
  \newcommand{\SetHeightDepthWidth}[1]{%   new
      \settoheight{\fillbox@height}{#1}%   new
      \settodepth{\fillbox@depth}{#1}%     new
      \settowidth{\fillbox@width}{#1}%     new
  }%

  \newcommand{\fillbox}[1]{%
  \ifmmode%                                             new
    \mathchoice%                                        new
        {\SetHeightDepthWidth{$\displaystyle#1$}}%      new
        {\SetHeightDepthWidth{$\textstyle#1$}}%         new
        {\SetHeightDepthWidth{$\scriptstyle#1$}}%       new
        {\SetHeightDepthWidth{$\scriptscriptstyle#1$}}% new
  \else%                                                new
    \SetHeightDepthWidth{#1}%                           new
  \fi%                                                  new
  %\ifmmode%
  %  \settoheight{\fillbox@height}{$#1$}%
  %  \settodepth{\fillbox@depth}{$#1$}%
  %  \settowidth{\fillbox@width}{$#1$}%
  %\else%
  %  \settoheight{\fillbox@height}{#1}%
  %  \settodepth{\fillbox@depth}{#1}%
  %  \settowidth{\fillbox@width}{#1}%
  %\fi%
  \raisebox{-\fillbox@depth}{%
    \begin{tikzpicture}[scale=1]
    \pgfsetfillcolor{yellow!90!red}
    \pgfsetfillopacity{0.5}
    \pgfsetrectcap
    \fill (0,-\fillbox@depth) rectangle (\fillbox@width,\fillbox@height);
    \pgfsetfillcolor{yellow!50!black}
    \pgfsetfillopacity{1}
    \fill (0,-\fillbox@depth)
          rectangle (\fillbox@width,-\fillbox@depth+.1pt);
    \fill (0,\fillbox@height)
          rectangle (\fillbox@width,\fillbox@height-.1pt);
    \fill (0,-\fillbox@depth)
          rectangle (.1pt,\fillbox@height);
    \fill (\fillbox@width,-\fillbox@depth)
          rectangle (\fillbox@width-.1pt,\fillbox@height);
    \end{tikzpicture}%
    \kern-\fillbox@width%
  }%
  #1%
}
\makeatother

\begin{document}

\vskip1em
$\fillbox{p}_{\fillbox{x}}
  \mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
  \fillbox{(}\fillbox{\frac{\fillbox{1}}{\fillbox{2}}}\fillbox{\cdot}
  \fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}^{\fillbox{2}}\fillbox{)} \fillbox{+}
  \fillbox{(}\fillbox{v}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}\fillbox{)}$\fillbox{;}\par
$\fillbox{v}_{\fillbox{x}}
  \mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
  \fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}$\fillbox{;}\par
%    
%            This section is not relevant to the problem here.
%\vskip1em
%$p_x \mathrel{\stackrel{_{~+}}{\leftarrow}}
%  (\frac{1}{2}\cdot a_x\cdot\Delta t^2) + (v_x\cdot\Delta t)$;\par
%$v_x \mathrel{\stackrel{_{~+}}{\leftarrow}} a_x\cdot\Delta t$;\par
%
\end{document}

Best Answer

\mathchoice acts at the end of the math list when TeX is making a horizontal list by putting the math boxes in the right places. So the "choice" happens way after you are attempting to use the lengths. (They are being set in a group and left as zero, but you can't simply make a global assignment as the timing is all wrong.)

Look at any uses of \mathchoice (or its wrapper \mathpalette) in plain or latex.ltx. The usual idiom is that you need to put the entire command including all its arguments so, using fbox for simplicity:

\def\fa#1{%
\mathchoice
  {\fbox{$\displaystyle#1$}}%
  {\fbox{$\textstyle#1$}}%
  {\fbox{$\scriptstyle#1$}}%
  {\fbox{$\scriptscriptstyle#1$}}}

would work, although usually you simplify things by defining a helper macro that takes the math style as an argument, for example in latex.ltx \smash in math mode uses this form with \mathsm@sh being a version of \smash that takes (eg) \scriptstyle as an additional argument. So something like

\def\xfb#1#2{\fbox{$#1#2$}}

\def\fb{\mathpalette\xfb}

Or you can let the AMS take care of you

\usepackage{amsmath}

\def\fc#1{\text{\fbox{$#1$}}}
Related Question