Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

It's common to use an \ifcase construct to redefine a command depending on the value of a counter. The following example illustrates this:

\documentclass{article}
\usepackage{xcolor}
\usepackage{etoolbox}

\newcommand\sectioncolor{}

\renewcommand\sectioncolor{%
  \ifcase\value{section} brown\or red\or blue\else olive\fi}
\pretocmd{\section}{\color{\sectioncolor}}{}{}

\begin{document}

\section{Section One}
\section{Section Two}
\section{Section Three}
\section{Section Four}

\end{document}

The above redefinition of \sectioncolor using \ifcase implies manually feeding the colors in the \ifcase construct. What I would like to achieve is to have a command, say \ColorList, having as argument a comma separated list of variable length containing the colors to be used, and then redefine \sectioncolor to use the colors of the list depending on the section counter. So for example, referring to my sample code, using

\ColorList{brown,red,blue,olive}

would be equivalent to

\renewcommand\sectioncolor{%
  \ifcase\value{section} brown\or red\or blue\else olive\fi}

and

\ColorList{yellow,magenta,cyan,orange,blue}

would be equivalent to

\renewcommand\sectioncolor{%
  \ifcase\value{section} yellow\or magenta\or cyan\or orange \else blue\fi}

but. of course, without having to manually feed the colors into the \ifcase. How can this be done?

share|improve this question
    
I was hopeful that Macro to access a specific member of a list would have solved this, but I am not able to adapt those solutions to work in this case. –  Peter Grill Apr 28 '12 at 2:05
add comment

7 Answers 7

up vote 14 down vote accepted

This is similar to @egreg's solution and avoids \ifcase in favour of just cycling the list, but the coding is probably a bit simpler (unless you'be already loaded expl3 for other reasons)

\documentclass{article}
\usepackage{xcolor}
\def\ColorList#1{\def\xcolorlist{#1}}
\let\xsection\section
\def\section{\expandafter\xxcycle\xcolorlist,\xcolorlist\xsection}
\def\xxcycle#1,#2{%
  \ifx\relax#1\relax\else
   \color{#1}%
   \ifx\xcolorlist#2\else
    \xcycle#1,#2%
   \fi
  \fi}


\def\xcycle#1,#2\fi\fi#3\xcolorlist{\fi\fi\ColorList{#2#3#1}}



\ColorList{yellow,magenta,cyan,orange,blue,green!30,red!50!black}
%\ColorList{yellow}
%\ColorList{}

\begin{document}

\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}

\end{document}
share|improve this answer
1  
I find that \ColorList{yellow} (ie, with only one member) fails. I don't know how important this is. Anyway, I have eked out a patch but I don't feel qualified to edit your answer. –  Ahmed Musa Apr 28 '12 at 23:36
    
@AhmedMusa thanks I fixed it (I hope) for {yellow} and {} edge cases. –  David Carlisle Apr 29 '12 at 0:20
add comment

Since you are using etoolbox already, you can use \docsvlist and redefine \do appropriately.

enter image description here

\documentclass{article}
\usepackage{xcolor}% http://ctan.org/pkg/xcolor
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox

\newcounter{listitem}
\newcommand\sectioncolor{%
  \setcounter{listitem}{-1}% At this point, section counter has not been incremented
  \renewcommand*{\do}[1]{%
    \stepcounter{listitem}% Increment list counter
    \ifnum\value{listitem}=\value{section}\color{##1}\fi% Match list counter with section counter
  }
  \docsvlist{yellow,magenta,cyan,orange,blue,green!30,red!50!black}%
}
\pretocmd{\section}{\sectioncolor}{}{}

\begin{document}

\section{Section One}
\section{Section Two}
\section{Section Three}
\section{Section Four}
\section{Section Five}
\section{Section Six}
\section{Section Seven}

\end{document}
share|improve this answer
    
Nice and clean, I was looking forward to this one while reading the other answers. –  ienissei Apr 29 '12 at 7:37
add comment

This will cycle over the listed colors:

\documentclass[convert,border=2,varwidth]{standalone}
\usepackage{xcolor,xpatch,xparse}
\xpretocmd{\section}{\sectioncolor}{}{}

\ExplSyntaxOn
\NewDocumentCommand{\ColorList}{m}
 {
  \seq_gset_split:Nnn \g_gonzalo_colors_seq { , } { #1 }
 }
\seq_new:N \g_gonzalo_colors_seq

\NewDocumentCommand{\sectioncolor}{ }
 {
  \seq_gpop_left:NN \g_gonzalo_colors_seq \l_tmpa_tl
  \seq_gput_right:NV \g_gonzalo_colors_seq \l_tmpa_tl
  \color { \l_tmpa_tl }
 }
\ExplSyntaxOff

\ColorList{yellow,magenta,cyan,orange,blue,green!30,red!50!black}

\begin{document}

\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}

\end{document}

At every call of \sectioncolor the color to use is popped from the top of the sequence and put back at the bottom.

enter image description here

share|improve this answer
add comment

There are probably a dozen standard methods for parsing comma-separated lists, but I don't know any of them, so here's my ad hoc solution (with a grain of salt :)

\makeatletter
\newcommand\@else@ifc{\noexpand\else}
\newcommand\@or@ifc{\noexpand\or}

\def\commalisttoifcase#1,%
{%
  #1\@commalisttoifcase
}

\def\@commalisttoifcase#1,#2,%
{%
  \ifx\empty#2\empty
    \@else@ifc\unexpanded{#1}%
    \expandafter\@gobble
   \else
    \@or@ifc\unexpanded{#1}%
    \expandafter\@commalisttoifcase
  \fi
  #2,%
}
\newcommand\ColorList[1]
{%
  \edef\next
  {%
    \noexpand\renewcommand\noexpand\sectioncolor{%
      \noexpand\ifcase\noexpand\value{section} 
      \commalisttoifcase#1,,\noexpand\fi
    }%
  }
  \next
}

\makeatother

Then

\ColorList{yellow,magenta,cyan,orange,blue}
\show\sectioncolor

gives

> \sectioncolor=\long macro:
->\ifcase \value {section} yellow\or magenta\or cyan\or orange\else blue\fi .
share|improve this answer
    
The LaTeX kernel uses @for, @for\next:=\alist\do{...}... –  Yiannis Lazarides Apr 28 '12 at 6:07
    
@YiannisLazarides I know that much, but I'd have to look in the code to find out whether it's expandable :-) –  Stephan Lehmke Apr 28 '12 at 6:34
add comment

Here is a simple solution using xstring. It does not do the proper error control (what happens if there are more sections than colors), but correctly processes the first and the last section:

\documentclass{article}
\usepackage{xstring}
\makeatletter
\def\ColorList#1{\gdef\@ColorList{#1}}
\def\sectioncolor{%
  \StrCount{\@ColorList}{,}[\@tempa]% The length of the
  \@tempcnta\@tempa\relax%                list
  \advance\@tempcnta by 1\relax
  \ifnum\the\c@section<2\relax\StrBefore{\@ColorList}{,}% The
                            % special case of first section 
  \else\ifnum\c@section=\the\@tempcnta\relax % The special case of
                            % last section 
    \advance\@tempcnta by -1\relax
    \StrBehind[\the\@tempcnta]{\@ColorList}{,}%
  \else  % The general case
    \@tempcntb=\the\c@section\relax
    \advance\@tempcntb by -1\relax
    \StrBetween[\the\@tempcntb,\the\c@section]{\@ColorList}{,}{,}%
  \fi\fi
}
\makeatother
\begin{document}
\pagestyle{empty}
\ColorList{brown,red,blue,olive}

\noindent\sectioncolor{}

\section{AAAA}

\sectioncolor{}

\section{BBBB}

\sectioncolor{}

\section{CCCC}

\sectioncolor{}

\section{DDDD}

\sectioncolor{}

\end{document}

enter image description here

share|improve this answer
add comment

In case you need more control, here is another solution.

\documentclass{article}
\usepackage[dvipsnames]{xcolor}
\usepackage{ltxkeys}
\usepackage{multicol}
\makeatletter
% Keys:
\ltxkeys@declarekeys[GM]{bodystyle}[bdsty@]{%
  cmd/body name/section/
    \edef\bdsty@bodyname{\unexpanded{#1}}%
    \ifltxkeys@dec\else
      \ifblankTF{#1}{%
        \@latexerr{Section body name can't be empty}\@ehd
      }{%
        \ifinsetTF{,#1,}{,chapter,section,subsection,paragraph,}{}{%
          \@latexerr{Section body name not recognized}\@ehd
        }%
      }
    \fi;
  cmd/style list command//
    \edef\bdsty@stylelistcommand{\unexpanded{#1}}%
    \ifltxkeys@dec\else
      \ifsingletokenFT{#1}{%
        \@latexerr{Style command \detokenize{#1} isn't a single token}\@ehd
      }{%
        \ifescapedTF{#1}{%
          \ifx#1\@undefined
            \@latexerr{Style command \detokenize{#1} is undefined}\@ehd
          \else
            \ifx#1\@empty
              \@latexerr{Style command \detokenize{#1} is empty}\@ehd
            \fi
          \fi
        }{%
          \@latexerr{Style command \detokenize{#1} isn't escaped}\@ehd
        }%
      }%
    \fi;
  cmd/repeated code//
    \edef\bdsty@repeatedcode{\unexpanded{#1}};
  cmd/exit code//
    \csn@edef{bdsty@\bdsty@bodyname @exitcode}{\unexpanded{#1}};
}

% User commands:
% \newbodystyle[<keyval>]
\newcommand\newbodystyle[1][]{%
  \ltxkeys@setkeys[GM]{bodystyle}{#1}%
  \cptexpanded{%
    \letcsntocsn{bodystyle@\bdsty@bodyname}{\bdsty@bodyname}%
    \csn@def{\bdsty@bodyname}{%
      \def\noexpand\n@wstylelist########1,########2\noexpand\newbodystyle{%
        \expandcsonce\bdsty@repeatedcode{########1}%
        \xdef\expandcsonce\bdsty@stylelistcommand{%
          \unexpanded{\ifblankTF{####2}{}{\unexpanded{####2},}%
          \unexpanded{####1}}%
        }%
      }%
      \noexpand\xifinsetTF{,}{\noexpand\expandcsonce
      \expandcsonce\bdsty@stylelistcommand}{%
        \unexpanded{\expandafter\n@wstylelist}\expandcsonce
          \bdsty@stylelistcommand\noexpand\newbodystyle
      }{%
        \unexpanded{\expandafter\n@wstylelist}\expandcsonce
          \bdsty@stylelistcommand,\noexpand\newbodystyle
      }%
      \noexpand\usename{bodystyle@\bdsty@bodyname}%
    }%
  }%
}
% \restorebodystyle{<body name list>}
\newcommand*\restorebodystyle[1]{%
  \cptdocommalist{#1}{%
    \ifcsndefTF{bodystyle@##1}{%
      \letcsntocsn{##1}{bodystyle@##1}%
      \csname bdsty@##1@exitcode\endcsname
    }{%
      \@latexerr{Heading name '\detokenize{##1}' wasn't saved}\@ehd
    }%
  }%
}
\makeatother

% Example document:
\begin{document}
% Fonts:
\def\usefontpallete{%
  \def\say{Current style: {\tt\detokenize\expandafter{\currstyle}}\par}%
  \def\sayb{\def\currstyle{normal font}\normalfont}%
  \def\style{\def\temp####1{\def\currstyle{####1}####1}\temp}%
  \def\sectionstylelist{\tt,\sf,\bf,\rm,\it,\mdseries}%
  \def\subsectionstylelist{\sl,\sc,\upshape}%
}
% Colors:
\def\usecolorpallete{%
  \def\say{Current color: {\tt\detokenize\expandafter{\currstyle}}\par}%
  \def\sayb{\def\currstyle{normal color}\normalcolor}%
  \def\style{\def\temp####1{\def\currstyle{####1}\color{####1}}\temp}%
  \def\sectionstylelist{orange,blue,red,red!50!black,ForestGreen}%
  \def\subsectionstylelist{olive,magenta,cyan}%
}
\parindent0pt
\begin{multicols}{2}
\section{Title}
Normal style, default style.

\usecolorpallete
% Let's ignore font pallete in the current run:
%\usefontpallete

\newbodystyle[
  body name          = section,
  style list command = \sectionstylelist,
  repeated code      = \style,
  % Code to execute when \restorebodystyle is called:
  exit code          = \sayb
]
\newbodystyle[
  body name          = subsection,
  style list command = \subsectionstylelist,
  repeated code      = \style,
  exit code          = \sayb
]
% A style may also be defined for 'paragraph'.

\section{Title}
\say aaa
\section{Title}
\say bbb
  % Higher order cycles (eg, subsection) are independent of lower order 
  % cycles (eg, section):
  \subsection{Subtitle}
  \say ccc
  \subsection{Subtitle}
  \say ddd
  \subsection{Subtitle}
  \say eee
  \subsection{Subtitle}
  \say fff
  \subsection{Subtitle}
  \say ggg
  % Restore subsection to default style:
  \restorebodystyle{subsection}
  \subsection{Subtitle}
  \say hhh
\section{Title}
\say iii
\section{Title}
\say jjj
\section{Title}
\say kkk
\restorebodystyle{section}
\section{Title}
\say lll
\section{Title}
\say mmm
\end{multicols}
\end{document}

enter image description here

Just for fun, here is a cyclic loop that won't bomb out:

\documentclass{article}
\usepackage{xcolor}
\usepackage{catoptions}
\makeatletter
\newif\ifcyclicstop
% \cyclicdo[<max loop run>]<callback><listcmd>
\robust@def*\cyclicdo{\cpt@testopt\@cyclicdo{10000}}
\robust@def\@cyclicdo[#1]#2#3{%
  \cyclicstopfalse
  \def\cyclicnr{0}%
  \def\@cyclica##1,##2{%
    \edef\cyclicnr{\the\numexpr\cyclicnr+1}%
    \ifnumcmpTF\cyclicnr>#1{%
      \@latexerr{Max loop number #1 exceeded by \string\cyclicdo}\@ehd
    }{%
      #2{##1}%
      \ifboolTF{cyclicstop}{%
        \begingroup
        \def\@cyclica####1\cyclicdo{\endgroup}%
        \let\@cyclicb\@cyclica
      }{}%
      \expandafter\ifcseqTF\cpt@car##2x\car@nil\cyclicdo{%
        \@cyclica##1,\cyclicdo
      }{%
        \@cyclicb##1,##2\@cyclicb
      }%
    }%
  }%
  \def\@cyclicb##1,##2\@cyclicb##3\cyclicdo{\@cyclica##2##3##1,\cyclicdo}%
  \ifcsemptyTF{#3}{}{\expandafter\@cyclica#3,\cyclicdo}%
}
\makeatother

% Example document:
\begin{document}
\def\colorlist{yellow,magenta,cyan,orange,blue,green!30,red!50!black}
%\def\colorlist{yellow}
%\def\colorlist{}
\def\do#1{%
  % Do only 10 cycles:
  \ifnum\cyclicnr>10\relax\cyclicstoptrue\fi
  {\color{#1}Current: \tt\detokenize{#1}}\endgraf
}
\cyclicdo\do\colorlist
\end{document}

enter image description here

share|improve this answer
add comment

ConTeXt provides \defineconversion and \convertnumber commands which cycle through the list of elements (or applies a macro to the number). This is useful for things like footnote markers (\dagger, \star, etc.), but can be easily overloaded for other tasks as well.

\defineconversion
  [colors]
  [red,blue,green]

\setuphead
  [section]
  [color={\convertnumber{colors}{\currentsectioncountervalue}}]

\starttext
\dorecurse{10}
  {\section{Section \recurselevel}}
\stoptext

which gives

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.