%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
% This is file 'skeyval-testpkg.sty', version 1.3, 2013/05/15.             %
%                                                                          %
% This package and accompanying files may be distributed and/or            %
% modified under the conditions of the LaTeX Project Public License,       %
% either version 1.3 of this license or any later version. The latest      %
% version of this license is in http://www.latex-project.org/lppl.txt      %
% and version 1.3 or later is part of all distributions of LaTeX           %
% version 2005/12/01 or later.                                             %
%                                                                          %
% The LPPL maintenance status of this software is 'author-maintained'.     %
%                                                                          %
% This software is provided 'as it is', without warranty of any kind,      %
% either expressed or implied, including, but not limited to, the          %
% implied warranties of merchantability and fitness for a particular       %
% purpose.                                                                 %
%                                                                          %
% The following files constitute the skeyval bundle and must be            %
% distributed as a whole:                                                  %
%                                                                          %
%  README, skeyval.sty, skeyval-core.tex, skeyval-for.tex,                 %
%  skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex,            %
%  skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls,          %
%  skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2,              %
%  skeyval-view-pokayoke1.                                                 %
%                                                                          %
% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com).                  %
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%

\ProvidesPackage{skeyval-testpkg}
  [2013/05/15 v1.3 skeyval test package (AM)]
\NeedsTeXFormat{LaTeX2e}
\@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}}
\RequirePackage{graphicx}

\skvdisabledkeysmessagetype{warning}

%%++++++++++++++++ Passing options to packages +++++++++++++++++++%%

\skvdeclarebooloption[SKVT]<testpkg>[skvtp@]{verbose}[true]{}

% Declare options with default values that will be used when the options
% are called without user values.
%
\skvdeclarepassedoptionsloadpackage[SKVT]{testpkg}{%
  hyperref={colorlinks,breaklinks},xcolor=svgnames
}

%%+++++++++++++++++++ Producing arbitrary texts +++++++++++++++++%%

% The key 'align' could have defined using \skvchoicekey, as in
% 'shadowbox' family below.
\newcommand*\justified{}
\skvordkey[SKVT]{abrtext}{align}[right]{%
  \skvifcase\skvxifstrcmpTF{#1}
    {left}{\def\mpfalign{flushleft}}
    {right}{\def\mpfalign{flushright}}
    {center}{\def\mpfalign{center}}
    {justified}{\def\mpfalign{justified}}
  \elsedo
    \PackageError{skeyval-testpkg}
      {Invalid value `#1' for align}
      {You have issued an illegal value `#1' for option `align'.}%
  \endif
}

\skvzcmdkey[SKVT]{abrtext}[mpf]{text style}[\rmfamily]{}
\skvcmdkey[SKVT]{abrtext}[mpf]{author}[Karl Berry]{}
\skvzboolkey[SKVT]{abrtext}[mpf]{show author}[true]{}

% Using pointers to expand values of keys while setting keys:
\def\alignval{right}
\def\alignvalb{\alignval}
\def\stextstyle{\sffamily}

\skvsetkeys[SKVT]{abrtext}{
  align=.expand twice{\alignvalb},
  text style=.expand once{\stextstyle},author,show author
}

%%+++++++++++++++++++++++++++ Citations +++++++++++++++++++++++++++%%

% Keys defined by \skvdefinekeys are automatically initialiized when
% the option 'initialize' is true. In general, to save initialize
% key values at key definition, you need to call \skvsaveinitialvaluekeys
% before defining the keys.

\skvsaveinitialvaluekeys[SKVT]{citation}{put frame,width,show author,author,
  textcolor,fonttype,leftmargin,rightmargin,preskip,framecolor,shadecolor,
  frame thickness}

\newbox\skv@testbox
\skvdefinekeys*[SKVT]{citation}[ctt@]{%
  .cmd/width/\hsize,
  .zbool/show author/true,
  .cmd/author//, % empty default
  .zbool/put frame/true,
  .cmd/framecolor/black,
  .cmd/shadecolor/white,
  .cmd/textcolor/black,
  .zcmd/frame thickness/.4pt,
  .cmd/fonttype/\normalfont,
  .cmd/leftmargin/\leftmargin,
  .cmd/rightmargin/\rightmargin,
  .cmd/preskip/0ex,
  .cmd/width/\textwidth,
  .ord/dummy key/\@nil,
}
% Keys defined by \skvdefinekeys are automatically initialiized when
% the option 'initialize' is true. When \skvsaveinitialvaluekeys has been
% called for a set of keys, those keys can be initialized via
% \skvinitializekeys:
\skvinitializekeys[SKVT]{citation}[dummy key]

\newcommand\newcitation[2][]{%
  \skvsetkeys[SKVT]{citation}{#1}%
  \sbox\skv@testbox{%
    \ctt@fonttype
    \textit{\textcolor{\ctt@textcolor}{\ctt@author}}%
  }%
  \list{}{%
    \setlength\leftmargin{\ctt@leftmargin}%
    \setlength\rightmargin{\ctt@leftmargin}%
  }%
  \vspace*{\ctt@preskip}%
  \item\relax
  \ifctt@putframe
    \begingroup
    \fboxrule\ctt@framethickness\relax
    \fcolorbox{\ctt@framecolor}{\ctt@shadecolor}{%
  \fi
  \parbox{\ctt@width}{%
    \ctt@fonttype\textcolor{\ctt@textcolor}{\ignorespaces#2}%
    \ifctt@showauthor
      \hspace*{\fill}\nolinebreak[1]%
      \quad\hspace*{\fill}\finalhyphendemerits\z@\relax
      \usebox\skv@testbox
    \fi
  }%
  \ifctt@putframe}\endgroup\fi
  \endlist
  % Restore default values of keys:
  \skvinitializekeys[SKVT]{citation}[]
}


%%++++++++++++++++++++++++ Shadow boxes ++++++++++++++++++++++%%

\newdimen\shadowspread

\skvdefinekeys*[SKVT]{shadowbox}[shb@]{%
  .zbool/put frame/true,
  .bool/shadow/true,
  .cmd/framecolor/black,
  .cmd/shadecolor/white,
  .cmd/shadowcolor/gray!55,
  .cmd/boxwidth/1.5cm,
  .ord/framesize/.5pt/\def\currfboxrule{#1},
  .ord/shadowsize/2pt/\shadowspread=\dimexpr#1\relax,
  .choice/align/center/{%
    center.do=\def\curralign##1{\hfil##1\hfil},
    right.do=\def\curralign##1{\hfill##1},
    left.do=\def\curralign##1{##1\hfill},
    justified.do=\let\curralign\@iden
  }
}

\skvdefinekeys*[SKVT]{testfam}[shb@]{%
  .zbool/put shadow/true,% Test zbool
  .zcmd/shade color/gray!55, % Test .zcmd
}

\skvdisablekeys[SKVT]{testfam}{put shadow, shade color}

% Presetting and posetting keys.
%
% 1. 'Presetting keys' means set the following keys whenever
%    \setkeys is called. These keys should be set BEFORE the keys
%    listed in the current argument of \setkeys are set, provided
%    that these keys aren't listed in the current argument of \setkeys.
%    If these keys appear in the current argument of \setkeys,
%    then obviously the user has new values for them or he wants
%    the keys to be set with their default values.
%
% 2. 'Postsetting keys' means set the following keys whenever
%    \setkeys is called. These keys should be set AFTER the keys
%    listed in the current argument of \setkeys are set, provided
%    that these keys aren't listed in the current argument of \setkeys.
%
% 3. The command \presetkeys of the xkeyval package expects both
%    'head' and 'tail'. The skeyval package splits \presetkeys into two,
%    hopefully less confusing, commands: \skvpresetkeys and
%    \skvpostsetkeys.
%
% 4. There is also command \skvpreposetkeys, which combines
%    \skvpresetkeys and \skvpostsetkeys. This expects both head and
%    tail and is equivalent to xkeyval's \presetkeys.

\skvpresetkeys[SKVT]{shadowbox}{%
  put frame,framecolor=black,framesize=.8pt,boxwidth=1.5cm,align=center,
  shadecolor=gray!15
}

\skvpostsetkeys[SKVT]{shadowbox}{%
  shadow=.use value{put frame},shadowcolor=.use value{framecolor}!40,
  shadowsize=\dimexpr.use value{framesize}*5\relax
}

\newcommand*\newshadowbox[2][]{%
  \skvsetkeys[SKVT]{shadowbox}{#1}%
  \begingroup
  \ifshb@putframe
    \fboxrule=\dimexpr\currfboxrule\relax
  \else
    \fboxrule=0pt
  \fi
  \ifshb@shadow\else\shadowspread=0pt \fi
  \sbox\z@{\fcolorbox{\shb@framecolor}{\shb@shadecolor}{%
    \hb@xt@\shb@boxwidth{\curralign{#2}}%
  }}%
  \hskip\shadowspread
  \color{\shb@shadowcolor}%
  \rule[-\dp0]{\wd0}{\dimexpr\ht0+\dp0\relax}%
  \llap{\raisebox{\shadowspread}{\box0\hskip\shadowspread}}%
  \endgroup
}

%%++++++++++++++++++++++++ The \directkeys command ++++++++++++++++++++%%

% The following are meant to demonstrate the use of the macro \directkeys:

\ifdefined\skvtestcnt
  \skvtestcnt\z@
\else
  \newcount\skvtestcnt
\fi
\def\logsetting{%
  \advance\skvtestcnt\@ne
  \typeout{'\skvcurrentkey' set: no.
    \ifnum\skvtestcnt<10 0\fi\the\skvtestcnt, %
    path: \skvcurrentprefix/\skvcurrentfamily}%
}

\directkeys{%
  % #1 will be the user-value of the handler 'some handler'.
  .new handlers = {
    .some handler=\def\x##1{##1*#1},
    .phantom handler=,
  },
  .handler let = {
    .another handler=.some handler,
    .do nothing handler=.phantom handler
  },
  .kill handlers={
    .another handler,
    .do nothing handler
  },
  .define handlers={
    .j handler=\def\x##1{##1*#1},
    .j handler=\def\y##1{##1*#1},
  },
  .define narg handlers={
    .j1 handler={2}{\def\x##1{##1*#1*#2}},
    .j2 handler={3}{\def\x##1{##1*#1*#2*#3}}
  },
  .new narg handlers={
    % Error: handler j1 already exists:
    % .j1 handler={2}{\def\x##1{##1*#1*#2}},
    .k handler={2}{\def\x##1{##1*#1*#2}},
    .l handler={3}{\def\x##1{##1*#1*#2*#3}}
  },
  .reserve handlers={reservedx , reservedy},
  .holder prefix = mp@,
  .prefix = KV,
  .families = {fam1, fam2},
  .add family = {fam3},
  .add families = {fama,famb,famc},
  .ignore families = {fama,famb,famc},
  .restore families = {fama,famb},
  .restore paths = {KVA/fama,KVD/famc},
%  .ignore keys = {keyb,keyc},
  .new keys = {
    .ord/keya/keya-default,
    .cmd/keyb/keyb-default/\def\x##1{##1#1},
    .cmd/keyc/keyc-default,
    .choice*/keyd/center
      /{  right.do=\def\val@r{#1},
          left.do=\def\val@l{#1},
          center.do=\def\val@c{#1}
        }
      /\def\yes{value accepted}
      /\def\no{value rejected},
    .bool/keye/true/
      \ifskvindef\else\logsetting\fi
      \ifmp@keye\def\y##1{##1#1}\fi
    ,
    .bool/keyf/true/,
    .bool/keyg/true/
  },
  .push path,
  .path = KV/fam1,
  .set keys = {keyd},
  .pop path,
  .ignore keys = {keyb,keyc},
  % Stop processing this list:
  % .list break,
  .restore keys = {keyb,keyc},
  .preset keys  = {keyb,keyc},
  .postset keys = {keyb,keyc},
  % Save unknown keys in the default macro \<pref>@<fam>@rmkeys:
  .save unknown keys = true,
  .save unknown keys in = \macroa,
  .set keys = {keya,keyb,keyc,keyd,keye},
  .set keys = {keya=keya-value,keyb=\def\y####1{####1}},
  .set keys* = {keya=keya-value,keyf},
  .set keys* = {keya=keya-value,keyf},
  .ignore keys = {keyf},
  .set rmkeys*,
  % Execute arbitrary code:
  .exec code=\def\x#1{#1},
  % Nesting of \directkeys is possible. Pre-entry and post-entry
  % topologies are independent. At the end of the nest,
  % prevailing variables of \directkeys revert to their previous
  % (pre-door) values:
  \directkeys{
    .paths = {KVA/fam3,KVB/fam3},
    .holder prefix = hp@,
    .define keys = {
      .cmd/keya/keya-default/\def\x##1{##1#1},
      .ord/keyb/keyb-default,
    },
    .set keys = {keya=vala},
  },
  .exec code = \def\keycval{true},
  % Prepend slot keye to key1 and key2:
  .prepend slot={key1/{keye=.expanded{\keycval}},key2/{keye=false}},
  % Multi-prepend slots:
  .prepend slot={{key3,key4}/{keye=true,keyf=true},key5/{keye=false}},
  % Prepend slot keyd to key6:
  .prepend slot={key6/{keyd=right}},
  % Append slots keye and keyf to key7 and key8.
  % '.slots' and '.slot' are equivalent to '.append slots'
  % and '.append slot'.
  .append slot={key7/{keye=true},key8/{keyf=false}},
  % The next two link keyb and keyc to key9. #1 here refers to the
  % current value of key9. The same effect can be achieved directly
  % via the '.link' handler:
  .prepend slot={key9/{keyb=#1}},
  .append slot={key9/{keyc=#1}},
  .set keys = {key9=val9},
  % Link keye and keyf to key10 and key11. The values of key10 and
  % key11 are used to set keye and keyf. key10 and key11 are hence
  % 'parent keys'.
  .link = {key10/keye, {key11,key12}/{keyf,keyg}},
  .set keys = {key10=true},
  .ignore key = keyf,
  .save unknown keys in = \macrob,
  .setkeys = {keya,keyb,keyf},
  .disable keys = {keye,keyf},
}

%%++++++++++++++++++++++ Collecting body of environment +++++++++++++++++%%

\skvmakekeys[
  .prefix=KV,
  .family=collectbody,
  .hp=mp,
  .initialize,
  .endlinechar=-1
]{%
  .cmd/title//,
  .zcmd/title scale/1,
  .zcmd/body scale/1,
  .cmd/width/\textwidth,
  .zcmd/title text style//,
  .zcmd/body text style//,
  .cmd/action//
}

\newsavebox{\boxbody}
\newenvironment{collectbody}[1][]{%
  \skvusekeys[.prefix=KV,.family=collectbody]{#1}%
  \ifx\mptitle\@empty\else\skvafterfi
    \begin{center}%
    \scalebox{\mptitlescale}{\mptitletextstyle\mptitle}%
    \end{center}%
  \fi
  \begin{lrbox}{\boxbody}%
  \begin{minipage}{\mpwidth}%
  \mpbodytextstyle\mpaction
}{%
  \end{minipage}%
  \end{lrbox}%
  \scalebox{\mpbodyscale}{\usebox{\boxbody}}%
}


%%+++++++++++++++++++++ Changing the key parser ++++++++++++++++++++%%

\setupskeyval{key parser={;}}
\skvafterdefinekeys{\setupskeyval{keyparser={,}}}
\skvdefinekeys*[SKVT]{example}[exm@]{%
  .zbool/put frame/true;
  .cmd/shadecolor/green;
  .ord/framesize/.5pt/\def\currfboxrule{#1};
  .choice/align/center/{%
    center.do=\def\curralign##1{\hfil##1\hfil},
    right.do=\def\curralign##1{\hfill##1},
    left.do=\def\curralign##1{##1\hfill},
    justified.do=\let\curralign\@iden
  };
}

%%++++++++++++++++++++++++++ Options section ++++++++++++++++++++++%%

\def\skvtp@unknownoptions{}

\skvunknownoptionhandler[SKVT]<abrtext,shadowbox,citation,testpkg>{%
  \edef\skvtp@unknownoptions{%
    \skvtp@unknownoptions\ifx\skvtp@unknownoptions\@empty\else,\fi
    #3%
  }%
  \AtEndDocument{%
    \ifx\skvtp@unknownoptions\@empty\else
      \PackageWarningNoLine{skeyval-testpkg}
        {Unknown keys: \skvtp@unknownoptions}%
    \fi
  }%
}
\skvexecuteoptions[SKVT]<abrtext>{align=.expanded{\alignval},
  text style=.expand once{\stextstyle},author,show author
}

\skvprocessoptions*+[SKVT]<abrtext,shadowbox,citation,testpkg>\relax
%\skvrestrictedprocessoptions*+[SKVT]<abrtext,shadowbox,citation,testpkg>\relax

\skvcomment
Here you could also use:

\directkeys{
  .mega process options*={
    .prefix=SKVT,
    .families={abrtext,shadowbox,citation,testpkg},
  }
}

or

\directkeys{
  .prefix=SKVT,
  .families={abrtext,shadowbox,citation,testpkg},
  .copy class options and process options in all families,
}
\endcomment

\endinput