2

Of late I have been troubling and unable to overcome an issue happening, when I want to open and end an environment inside a \newcommand with multiple optional arguments:

\documentclass[10pt,a4paper]{article}
\usepackage{caption}
\usepackage{geometry}
\usepackage{float}
\geometry{
a4paper,
total={170mm,257mm},
left=20mm,
top=20mm}
\usepackage[dvi-ps]{graphicx}
\usepackage[utf8]{inputenc}
\newfloat{obraz}{TBPH}{obr}
\floatname{obraz}{Obraz}
\newcommand{\obrc}[5][H][3.5]{\begin{obraz}[#1]
\centering
\includegraphics[width=#2 in]{#3}
\caption{#4}
\label{#5}
\end{obraz}}

As I need to put a lot of figures into docs, I wanted it to be simpler, but I am getting a handful of errors, starting with:

Missing \begin{document}. \newcommand{\obrc}[5][H][3

Missing \begin{document}. ...ommand{\obrc}[5][H][3.5]{\begin{obraz}[#1]

Illegal parameter number in definition of \@fps. ...ommand{\obrc}[5][H][3.5]{\begin{obraz}[#1]

Any ideas how to make it work?

  • 1
    The problem is with the [3.5]. \newcommand takes only two optional arguments: the number of arguments, and the default value of the first optional. – Phelype Oleinik Oct 9 '18 at 20:54
3

With LaTeX's \newcommand you can't define more than one optional argument. You can use xparse's \NewDocumentCommand:

\documentclass[10pt,a4paper]{article}
\usepackage{caption}
\usepackage{geometry}
\usepackage{float}
\geometry{
a4paper,
total={170mm,257mm},
left=20mm,
top=20mm}
\usepackage{graphicx}
\usepackage[utf8]{inputenc}
\newfloat{obraz}{TBPH}{obr}
\floatname{obraz}{Obraz}

\usepackage{xparse}
\NewDocumentCommand{\obrc}{
  O{H} % Optional, delimited by [], if not given use H
  D(){3.5} % Optional, delimited by (), if not given use 3.5
  m% Mandatory
  m% Mandatory
  m% Mandatory
  }{%
  \begin{obraz}[#1]
    \centering
    \includegraphics[width=#2 in]{#3}
    \caption{#4}
    \label{#5}
  \end{obraz}%
}

\begin{document}

\obrc{example-image}{No optional arguments}{hello1}

\obrc[p]{example-image}{First optional argument}{hello2}

\obrc(2){example-image}{Second optional argument}{hello3}

\obrc[b](1){example-image}{Both optional arguments}{hello4}

\end{document}

The O{H} means that the first argument will be Optional (and delimited by [] as in LaTeX), and the default value, if not given, will be H. The D(){3.5} means that the second argument will be optional and Delimited by (), and the default will be 3.5. The other three m mean that the command will take three more mandatory arguments.

You could change the second argument from D(){3.5} to O{3.5}, then the command would be called with \obrc[b][1]{... but then you wouldn't be able to use the second argument without using the first one.

  • 1
    Thank you, that was solved all my problems! – Smoksul Oct 9 '18 at 22:03
1

The easiest way to achieve your requested input is to use xparse. This allows you to specify multiple optional arguments (with defaults) in the following way:

\usepackage{xparse}

\NewDocumentCommand{\obrc}{ O{H} O{3.5} m m m }{%
  <\obrc definition>
}

The parameter O{<default>} defines an Optional argument with a pre-specified <default> value. Here's a complete example matching your use-case:

enter image description here

\documentclass{article}

\usepackage{float,graphicx}
\usepackage{xparse}

\newfloat{obraz}{tbpH}{obr}
\floatname{obraz}{Obraz}

\NewDocumentCommand{\obrc}{ O{H} O{3.5} m m m }{%
  \begin{obraz}[#1]
    \centering
    \includegraphics[width=#2 in]{#3}
    \caption{#4}%
    \label{#5}
  \end{obraz}%
}

\begin{document}

\obrc{example-image}{Example image}{fig:example-image}

\end{document}

It often becomes awkward when having more than one optional argument, since you can't specify the second optional argument without also specifying the first, otherwise there's no way to distinguish which is which. However, this removes the luxury of specifying a default value if you have to specify it anyway. In such circumstances, it's almost better to create a command that takes a key-value optional argument with some (set of) mandatory argument(s). Here's an example that matches your use-case:

enter image description here

\documentclass{article}

\usepackage{float,graphicx}
\usepackage{xkeyval}

\newfloat{obraz}{tbphH}{obr}
\floatname{obraz}{Obraz}

\makeatletter
\define@cmdkey{obraz}{alignment}{}
\define@cmdkey{obraz}{float}{}
\define@cmdkey{obraz}{width}{}
\define@cmdkey{obraz}{caption}{}
\define@cmdkey{obraz}{label}{}

\newcommand{\obrc}[2][]{%
  \setkeys{obraz}{%
    float = H, % Defaut float
    width = 3.5in, % Default width
    alignment = \centering, % Default horizontal alignment
    caption = \relax, % Default caption (no caption)
    label = \relax, % Default label (no label)
    #1
  }%
  \edef\x{\noexpand\begin{obraz}[\cmdKV@obraz@float]}\x
    \cmdKV@obraz@alignment
    \includegraphics[width=\cmdKV@obraz@width]{#2}
    \ifx\cmdKV@obraz@caption\relax\else
      \caption{\cmdKV@obraz@caption}%
      \expandafter\ifx\cmdKV@obraz@label\relax\else
        \label{\cmdKV@obraz@label}% A \label without a \caption doesn't make sense, hence the nesting
      \fi
    \fi
  \end{obraz}%
}
\makeatother

\begin{document}

\obrc[%
  caption = Example image,
  label = fig:example-image%
]{example-image-a}

\obrc[%
  width = 2in,
  alignment = \raggedright,
  caption = {Example image, left-aligned}
]{example-image-b}

\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.