[Tex/LaTex] List with several types of items

listsvertical alignment

How can one create a list with different types of items ?
I am using the package enumitem, which is great for defining items and referring to them, but it seems to allow only one type of item. I have looked in the definition of \item in latex.ltx, but could not find any useful hint, and in enumitem.sty neither.

More concretely I wish to have items like

   1 ...
 → 2 ...
 ✓ 3 ...

and type

\normalitem ...
\arrowitem ...
\checkeditem ...

Currently, I use \item[\refstepcounter{xi}$\symbol$\arabic{thexi}]
Is there a better way to do it ?

Best Answer

Improved version:

The idea is still the same that I used in the first version (see below), but now the process is completely transparent for the final user; in particular, no extra packages are needed (pifont and tikz were only loaded in my example to get fancy symbols) and new item types are now defined simply by using

\newitem{<prefix>}{<symbol>}

where <prefix> is the alphabetic string that will be used to call the new item, and <symbol> is the symbol that will be pre-pended to the label.

\documentclass{article}
\usepackage{pifont}
\usepackage{tikz}

\newcommand\myinfo{%
  \tikz[baseline]\node (info) [anchor=base,shape=circle,draw=orange!20,inner sep=1pt,fill=orange,text=white] {\bfseries\sffamily !};%
}

\makeatletter
\newcommand\newitem[2]{%
  \expandafter\def\csname#1item\endcsname{%
    \expandafter\@inmatherr\csname #1item\endcsname%
    \@ifnextchar[{\csname @#1item\endcsname}{\@noitemargtrue\csname @#1item\endcsname[\@itemlabel]}}%
\expandafter\def\csname @#1item\endcsname[##1]{%
\if@noparitem
\@donoparitem
\else
\if@inlabel
\indent \par
\fi
\ifhmode
\unskip\unskip \par
\fi
\if@newlist
\if@nobreak
\@nbitem
\else
\addpenalty\@beginparpenalty
\addvspace\@topsep
\addvspace{-\parskip}%
\fi
\else
\addpenalty\@itempenalty
\addvspace\itemsep
\fi
\global\@inlabeltrue
\fi
\everypar{%
\@minipagefalse
\global\@newlistfalse
\if@inlabel
\global\@inlabelfalse
{\setbox\z@\lastbox
\ifvoid\z@
\kern-\itemindent
\fi}%
\box\@labels
\penalty\z@
\fi
\if@nobreak
\@nobreakfalse
\clubpenalty \@M
\else
\clubpenalty \@clubpenalty
\everypar{}%
\fi}%
\if@noitemarg
\@noitemargfalse
\if@nmbrlist
\refstepcounter\@listctr
\fi
\fi
\sbox\@tempboxa{\makelabel{#2\kern1pt##1}}%
\global\setbox\@labels\hbox{%
\unhbox\@labels
\hskip \itemindent
\hskip -\labelwidth
\hskip -\labelsep
\ifdim \wd\@tempboxa >\labelwidth
\box\@tempboxa
\else
\hbox to\labelwidth {\unhbox\@tempboxa}%
\fi
\hskip \labelsep}%
\ignorespaces}
}
\makeatother

\newitem{diamond}{\ding{70}}
\newitem{arrow}{$\to$}
\newitem{checked}{\ding{51}}
\newitem{info}{\myinfo}

\begin{document}

\begin{enumerate}
\arrowitem First item.
\item Second item.
\checkeditem Third item.
\item Fourth item.
  \begin{enumerate}
  \item First subitem.
  \arrowitem[($\ast$)] Second subitem.
  \checkeditem Third subitem.
\end{enumerate}
\arrowitem Fifth item.
\item Sixth item.
\infoitem Seventh item.
\checkeditem Eighth item.
\end{enumerate}

\end{document}

enter image description here

This solution has an advantage and it is that it can be used on its own (without the enumitem package), but it is compatible with the use of this package, if one decides to use it, as the following example demonstrates:

\documentclass{article}
\usepackage{pifont}
\usepackage{tikz}
\usepackage{enumitem}

\newcommand\myinfo{%
  \tikz[baseline]\node (info) [anchor=base,shape=circle,draw=orange!20,inner sep=1pt,fill=orange,text=white] {\bfseries\sffamily !};%
}

\makeatletter
\newcommand\newitem[2]{%
  \expandafter\def\csname#1item\endcsname{%
    \expandafter\@inmatherr\csname #1item\endcsname%
    \@ifnextchar[{\csname @#1item\endcsname}{\@noitemargtrue\csname @#1item\endcsname[\@itemlabel]}}%
\expandafter\def\csname @#1item\endcsname[##1]{%
\if@noparitem
\@donoparitem
\else
\if@inlabel
\indent \par
\fi
\ifhmode
\unskip\unskip \par
\fi
\if@newlist
\if@nobreak
\@nbitem
\else
\addpenalty\@beginparpenalty
\addvspace\@topsep
\addvspace{-\parskip}%
\fi
\else
\addpenalty\@itempenalty
\addvspace\itemsep
\fi
\global\@inlabeltrue
\fi
\everypar{%
\@minipagefalse
\global\@newlistfalse
\if@inlabel
\global\@inlabelfalse
{\setbox\z@\lastbox
\ifvoid\z@
\kern-\itemindent
\fi}%
\box\@labels
\penalty\z@
\fi
\if@nobreak
\@nobreakfalse
\clubpenalty \@M
\else
\clubpenalty \@clubpenalty
\everypar{}%
\fi}%
\if@noitemarg
\@noitemargfalse
\if@nmbrlist
\refstepcounter\@listctr
\fi
\fi
\sbox\@tempboxa{\makelabel{#2\kern1pt##1}}%
\global\setbox\@labels\hbox{%
\unhbox\@labels
\hskip \itemindent
\hskip -\labelwidth
\hskip -\labelsep
\ifdim \wd\@tempboxa >\labelwidth
\box\@tempboxa
\else
\hbox to\labelwidth {\unhbox\@tempboxa}%
\fi
\hskip \labelsep}%
\ignorespaces}
}
\makeatother

\newitem{diamond}{\ding{70}}
\newitem{arrow}{$\to$}
\newitem{checked}{\ding{51}}
\newitem{info}{\myinfo}

\setlist[enumerate,1]{label=\roman*.}
\setlist[enumerate,2]{label=(\arabic*)}

\begin{document}

\begin{enumerate}
\arrowitem First item.
\item Second item.
\checkeditem Third item.
\item Fourth item.
  \begin{enumerate}
  \item First subitem.
  \arrowitem[($\ast$)] Second subitem.
  \checkeditem Third subitem.
\end{enumerate}
\arrowitem Fifth item.
\item Sixth item.
\infoitem Seventh item.
\checkeditem Eighth item.
\end{enumerate}

\end{document}

enter image description here

The first (preliminary) solution:

\documentclass{article}
\usepackage{pifont}
\usepackage{xpatch}

\makeatletter
\def\arrowitem{%
\@inmatherr\arrowitem
\@ifnextchar [\@arrowitem{\@noitemargtrue \@arrowitem[\@itemlabel]}}
\let\@arrowitem\@item
\xpatchcmd{\@arrowitem}
  {\makelabel{#1}}
  {\makelabel{$\to$\kern1pt#1}}
  {}
  {}

\def\checkeditem{%
\@inmatherr\checkeditem
\@ifnextchar [\@checkeditem{\@noitemargtrue \@checkeditem[\@itemlabel]}}
\let\@checkeditem\@item
\xpatchcmd{\@checkeditem}
  {\makelabel{#1}}
  {\makelabel{\ding{51}\kern1pt#1}}
  {}
  {}
\makeatother

\begin{document}

\begin{enumerate}
\arrowitem First item.
\item Second item.
\checkeditem Third item.
\item Fourth item.
  \begin{enumerate}
  \item First subitem.
  \arrowitem[($\ast$)] Second subitem.
  \checkeditem Third subitem.
\end{enumerate}
\arrowitem Fifth item.
\item Sixth item.
\item Seventh item.
\checkeditem Eighth item.
\end{enumerate}

\end{document}

enter image description here

The idea is to create copies of the original \item and \@item commands and then patch the copies to include the desired symbol.

(I shamelesly borrowed azetina's \myinfo command from his answer).

Related Question