3

I have a problem with capturing returned value of my command.

Here is my preamble with command definition:

\documentclass[convert={density=300,size=800x600,outext=.png}]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz}

% Font used for writing commands.
\def\cmdFont{\fontsize{10}{12}\selectfont}

% Commands.
\def\cmdOne  {\cmdFont aaa}
\def\cmdTwo  {\cmdFont bbbbb}
\def\cmdThree{\cmdFont cccc}

% Function which returns maximum width needed to write any of provided arguments.
\makeatletter

    \newlength{\textLength@getMaximumWidthHelper}
    \newlength{\textLength@getMaximumWidth}

    \newcommand{\getMaximumWidthHelper}[2]
    {%
        \settowidth{\textLength@getMaximumWidthHelper}{\pgfinterruptpicture #2\endpgfinterruptpicture}%

        \pgfmathparse{max(#1,\textLength@getMaximumWidthHelper)}%
        \@ifnextchar\bgroup{\getMaximumWidthHelper{\pgfmathresult pt}}{\pgfmathresult pt}%
    }%

    \newcommand{\getMaximumWidth}[1]
    {%
        \settowidth{\textLength@getMaximumWidth}{\pgfinterruptpicture #1\endpgfinterruptpicture}%
        \@ifnextchar\bgroup{\getMaximumWidthHelper{\the\textLength@getMaximumWidth}}{\the\textLength@getMaximumWidth}%
    }%

\makeatother

Working example used to test the above command:

\begin{document}

    \getMaximumWidth{\cmdOne}
    \getMaximumWidth{\cmdOne}{\cmdTwo}
    \getMaximumWidth{\cmdOne}{\cmdTwo}{\cmdThree}

\end{document}

However, when I try to capture the output of getMaximumWidth, it doesn't work as expected.

\begin{document}

    \newlength{\maximumWidth}
    \setlength{\maximumWidth}{\getMaximumWidth{\cmdOne}{\cmdTwo}{\cmdThree}}
    \the\maximumWidth

\end{document}

On the second line, the return value of getMaximumWidth is not captured but instantly printed.
Afterwards I get an error:

! Missing number, treated as zero.

After that, the third line just prints default value 0.0pt.

What is the proper way to capture the output of getMaximumWidth?

P.S. This is my first time writing Latex document, feel free to point out anything i could've done better.

  • 1
    while \@ifnextchar\bgroup works you should almost never do it as it results in commands that fail to obey latex syntax conventions. All latex commands have a fixed number of arguments using {} delimiters and a variable number of optional arguments which use [] delimiters. You have defined a command with optional {} arguments which is wrong. – David Carlisle Apr 24 at 14:37
  • macros do not have return values, your \getMaximumWidth expands to a series of assignments so is not a length that can be used in \setlength, you need to define it to leave a length in some command, say \tempresult then use \getMaximumWidth{\cmdOne}{\cmdTwo}{\cmdThree}\setlength{\maximumWidth}{\tempresult} or using a latex-conforming syntax, \getMaximumWidth{\cmdOne,\cmdTwo,\cmdThree}\setlength{\maximumWidth}{\tempresult} – David Carlisle Apr 24 at 15:43
  • That is exactly why \pgfmathparse leaves its answer in \pgfmathresult – David Carlisle Apr 24 at 15:45
  • Thanks a lot! I am not able to test everything at the moment, but your solution seems a lot easier and can be used as I intended. – Iskustvo Apr 24 at 16:00
5

I'd generalize \settowidth and, by the way, get also height and depth for free.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\settomaximumwidth}{mm}
 {% #1 = length, #2 = comma separated list of objects
  \iskustvo_settomaxdim:Nnn \settowidth { #1 } { #2 }
 }
\NewDocumentCommand{\settomaximumheight}{mm}
 {% #1 = length, #2 = comma separated list of objects
  \iskustvo_settomaxdim:Nnn \settoheight { #1 } { #2 }
 }
\NewDocumentCommand{\settomaximumdepth}{mm}
 {% #1 = length, #2 = comma separated list of objects
  \iskustvo_settomaxdim:Nnn \settodepth { #1 } { #2 }
 }

\dim_new:N \l__iskustvo_tempa_dim
\dim_new:N \l__iskustvo_tempb_dim
\tl_new:N \l__iskustvo_temp_tl

\cs_new_protected:Nn \iskustvo_settomaxdim:Nnn
 {
  \dim_zero:N \l__iskustvo_tempa_dim
  \clist_map_variable:nNn { #3 } \l__iskustvo_temp_tl
   { \__iskustvo_measure:N #1 }
  \dim_set_eq:NN #2 \l__iskustvo_tempa_dim
 }
\cs_new_protected:Nn \__iskustvo_measure:N
 {
  #1{\l__iskustvo_tempb_dim}{\l__iskustvo_temp_tl}
  \dim_set:Nn \l__iskustvo_tempa_dim
   {
    \dim_max:nn { \l__iskustvo_tempa_dim } { \l__iskustvo_tempb_dim }
   }
 } 
\ExplSyntaxOff

% Font used for writing commands.
\def\cmdFont{\fontsize{10}{12}\selectfont}

% Commands.
\def\cmdOne  {\cmdFont aaa}
\def\cmdTwo  {\cmdFont bbbbb}
\def\cmdThree{\cmdFont cccc}

\begin{document}

\newlength{\test}

\settomaximumwidth{\test}{\cmdOne,\cmdTwo,\cmdThree}
\the\test

\settomaximumheight{\test}{\cmdOne,\cmdTwo,\cmdThree}
\the\test

\settomaximumdepth{\test}{\cmdOne,\cmdTwo,\cmdThree}
\the\test

\end{document}

enter image description here

  • 2
    Thank you! I won't lie, I have absolutely no idea what you did, but the usage at the end is pretty neat. – Iskustvo Apr 24 at 17:22
  • I've read a bit and now that I understand what you did with this Elvish syntax, it's even more impressive! Luckily I think I'll just need the width, so I'll dumb it down a little. – Iskustvo Apr 25 at 19:30
6

I would write this something like

enter image description here

\documentclass{article}

\newcommand\cmdFont{\fontsize{10}{12}\selectfont}% this is the default anyway

% Commands.
\newcommand\cmdOne  {\cmdFont aaa}
\newcommand\cmdTwo  {\cmdFont bbbbb}
\newcommand\cmdThree{\cmdFont cccc}


\newlength{\maximumWidth}

\newcommand{\getMaximumWidth}[1]{%
\settowidth\maximumWidth{\begin{tabular}{@{}l@{}}#1\end{tabular}}}

\begin{document}

\getMaximumWidth{\cmdOne\\ \cmdTwo\\ \cmdThree}

\the\maximumWidth

\end{document}

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.