6

If I define some (many) keys with xkeyval do I really have to initialize them to use them if the key is not set explicitly?

\documentclass{article}

\usepackage{xkeyval}

\makeatletter
\define@cmdkeys{fam}[my@]{%
   fonta,
   fontb,
   % ...
   % fontn
}[]

%\presetkeys{fam}{keya,keyb}{}

%\setkeys{fam}{
%   fonta,
%   fontb,
%   % ...
%   % fontn
%}


\newcommand{\mymacro}[2]{%
   {\my@fonta #1} and {\my@fontb #2}
}
\makeatother



\begin{document}
\mymacro{Font A}{Font B}
\end{document}

This code shall become part of a new package. Many of my keys should set a font, which is empty per default (i.i. if the user doesn’t sets a key-value pair for it). I want to use these font’s in macro definitions but I have to initialize all fonts manually as empty. As a result of this behavior I need to take care of two lists (\define@cmdkeys and \setkeys) in case of adding a new font.

In my understanding the above example should compile as it is but I need to uncomment the \setkeys lines to initialize the macros.

Certainly there are keys that must have a preset value and i must initialize them. For example savemode well be a boolean that is false in preset but should default to true if the user set the key without a value.


Extra What does \presetkeys do? I don’t understand the manual in this section. Is it better to post this as a new question?

Tobi
  • 56,353
  • Is your concern that you want to use the values of these keys without worrying whether they are set; And, you don't know which ones to set to the default since the user may set some (not all) of them? – Werner Mar 03 '12 at 02:49
  • The default is an empty definition. I’ll change the example to pint this out. – Tobi Mar 03 '12 at 10:02

1 Answers1

4

The xkeyval doesn't provide for auto-initialization of keys. Your best bets are the keyreader and ltxkeys packages; they provide commands that automatically initialize keys to their default values after the keys have been defined. The keyreader package is easier to follow than the ltxkeys package, but of course has fewer features. Here is an example based on the keyreader (and xkeyval) package.

\documentclass{article}
\usepackage{keyreader}
\usepackage{xcolor}
\makeatletter
\newdimen\shadowsize
\define@boolkey[KV]{shadowbox}[shb@]{frame}[true]{}
\define@boolkey[KV]{shadowbox}[shb@]{shadow}[true]{}
\define@cmdkey[KV]{shadowbox}[shb@]{framecolor}[black]{}
\define@cmdkey[KV]{shadowbox}[shb@]{shadecolor}[white]{}
\define@cmdkey[KV]{shadowbox}[shb@]{shadowcolor}[gray]{}
\define@cmdkey[KV]{shadowbox}[shb@]{boxwidth}[2cm]{}
\define@choicekey+[KV]{shadowbox}{align}[\val\nr]
  {center,right,left,justified}[center]{%
  \ifcase\nr\relax
    \def\curralign##1{\hfil##1\hfil}%
  \or
    \def\curralign##1{\hfill##1}%
  \or
    \def\curralign##1{##1\hfill}%
  \or
    \let\curralign\@iden
  \fi
}{%
  \@latex@error{Erroneous value for a choice key}
    {Invalid value '#1' for key 'align' of family '\XKV@tfam'}%
}
% The following keys could have been defined as command keys, but this is
% just an illustration:
\define@key[KV]{shadowbox}{framesize}{\def\currfboxrule{#1}}
\define@key[KV]{shadowbox}{shadowsize}{\shadowsize=\dimexpr#1\relax}

% Save the values of the following keys when they are being set:
\savevaluekeys[KV]{shadowbox}{frame,framecolor,framesize}

% '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.

% The command \presetkeys of the xkeyval package expects both 'head' and 'tail'.
% The keyreader package splits \presetkeys into two, hopefully less confusing,
% commands: \krdpresetkeys and \krdpostsetkeys.

\krdpresetkeys[KV]{shadowbox}{%
  frame,framecolor=black,framesize=.8pt,boxwidth=2cm,align=center,
  shadecolor=gray!15
}
% '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:
\krdpostsetkeys[KV]{shadowbox}{%
  shadow=\usevalue{frame},shadowcolor=\usevalue{framecolor}!40,
  shadowsize=\dimexpr\usevalue{framesize}*5\relax
}
\newcommand*\newshadowbox[2][]{%
  \krdsetkeys[KV]{shadowbox}{#1}%
  \begingroup
  \ifshb@frame
    \fboxrule=\dimexpr\currfboxrule\relax
  \else
    \fboxrule=0pt
  \fi
  \ifshb@shadow\else\shadowsize=0pt \fi
  \sbox\z@{\fcolorbox{\shb@framecolor}{\shb@shadecolor}{%
    \hb@xt@\shb@boxwidth{\curralign{#2}}%
  }}%
  \hskip\shadowsize
  \color{\shb@shadowcolor}%
  \rule[-\dp0]{\wd0}{\dimexpr\ht0+\dp0\relax}%
  \llap{\raisebox{\shadowsize}{\box0\hskip\shadowsize}}%
  \endgroup
}
\makeatother

\begin{document}
\noindent
\newshadowbox{tobi1}
\newshadowbox[framecolor=gray,shadecolor=blue!25,shadowsize=10pt,align=left]{tobi2}
\newshadowbox[shadow=false,boxwidth=1cm]{tobi3}
\newshadowbox[framesize=2pt,framecolor=red,shadowcolor=green]{tobi4}
\newshadowbox[frame=false,shadow,shadowsize=9pt,shadowcolor=violet!50,align=right]{tobi5}
\end{document}


% Using a feature of the keyreader package, all the above keys can be defined 
% compactly as follows. The command \krddefinekeys will automatically initialize
% the keys after they have been defined.
\krddefinekeys*[KV]{shadowbox}[shb@]{%
  bool/frame/true;
  bool/shadow/true;
  cmd/framecolor/black;
  cmd/shadecolor/white;
  cmd/shadowcolor/gray;
  cmd/boxwidth/2cm;
  ord/framesize/.5pt/\def\currfboxrule{#1};
  ord/shadowsize/2pt/\shadowsize=\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;
} 

enter image description here

Ahmed Musa
  • 11,742
  • Thanks! Your example seems to be not very different to the xkeyval equivalent. I’ll have a look at the documentation later and decide wether to keep xkeyval or change to keyreader. – Tobi Mar 03 '12 at 14:34
  • @Tobi: Yes, I wanted an example that looks like the one xkeyval users would have seen in the xkeyval documentation or in http://www.tug.org/TUGboat/tb25-2/tb81adriaens.pdf. – Ahmed Musa Mar 03 '12 at 15:00
  • Hi, I had a look at it and either I don’t understand the package or I found a bug … See http://tex.stackexchange.com/q/46703/4918 please. – Tobi Mar 04 '12 at 00:04