22

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 ?

1
  • As I am too lazy to manage complex macros as those of the great answers (+1), just after \item I would add macros making something like \hspace{-2em}\llap{$\rightarrow$}\hspace{2em}. Simplistic and limited, but simple. :)
    – Fran
    Jan 21, 2014 at 7:38

2 Answers 2

20

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

10
  • Thanks for this preliminary answer. I'm looking forward to the definitive one. Could we imagine an additional macro (to enumitem for instance) that would create the item in a more comprehensive way like \newitem{listname}{\itemname}{label=$\to$\arabic*.,ref=\arabic*} ?
    – Tom-Tom
    Jan 20, 2014 at 16:19
  • @GonzaloMedina Ah sorry, I didn't read the question correctly, +1 b.t.w
    – user42341
    Jan 20, 2014 at 18:32
  • Could you elaborate on what each line of the code is doing? I would really like to understand this as it may be applicable else where.
    – azetina
    Jan 20, 2014 at 19:36
  • @V.Rossetto I added to my answer an improved version; now you can easily build as many new item types as you like with a simple command \newitem{<prefix>}{<symbol>}, as you requested. Jan 20, 2014 at 22:21
  • @azetina I was producing an improved version of the code (which now I've added to my answer); I will add some brief explanatory comments later. Jan 20, 2014 at 22:23
17

Here is an alternative MWE:

enter image description here

\documentclass[letterpaper]{article}
\usepackage{tikz}
\usepackage{pifont}
\usepackage{enumitem}
\setlist[enumerate]{before=\setupmodenumerate}

\newif\ifmoditem
\newcommand{\setupmodenumerate}{%
  \global\moditemfalse
  \let\origmakelabel\makelabel
  \def\moditem##1{\global\moditemtrue\def\mesymbol{##1}\item}%
  \def\makelabel##1{%
    \origmakelabel{\ifmoditem\llap{\mesymbol\enspace}\fi##1}%
    \global\moditemfalse}%
}
\newcommand{\myinfo}{\tikz[baseline] \node (info) [anchor=base,shape=circle,draw=orange!20,inner sep=1pt,fill=orange,text=white] {\bfseries\sffamily !};}
\begin{document}
\begin{enumerate}
    \item One
    \moditem{$\to$} Two
        \begin{enumerate}
            \item Two A
            \moditem{$\to$}[($\ast$)] Two B
            \item Two C 
        \end{enumerate}
    \moditem{\ding{51}} Three
    \moditem{\myinfo} Four
\end{enumerate}
\end{document}

The convenience of the command defined above is that you only need one and its argument carries the special items desired. I added an example with an image using TikZ, just for fun. The \moditem command also works with sublevels as illustrated above.

Note: I had asked something similar: Add an asterisk left of an enumerate and the solution given by @egreg here.

3
  • Thanks for this nice answer. I did checked if the question had been already asked, probably with bad keywords.
    – Tom-Tom
    Jan 20, 2014 at 16:38
  • @V.Rossetto Its ok. Thumbs up because you got a new answer in a different approach. So, everyone can learn the different possibilities.
    – azetina
    Jan 20, 2014 at 16:39
  • Honestly I think this answer works better and should be the accepted one Apr 15, 2022 at 21:42

You must log in to answer this question.

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