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.

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?

share|improve this question
    
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 3 '12 at 2:49
    
The default is an empty definition. I’ll change the example to pint this out. –  Tobi Mar 3 '12 at 10:02
add comment

1 Answer

up vote 4 down vote accepted

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

share|improve this answer
    
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 3 '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 tug.org/TUGboat/tb25-2/tb81adriaens.pdf. –  Ahmed Musa Mar 3 '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 tex.stackexchange.com/q/46703/4918 please. –  Tobi Mar 4 '12 at 0:04
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.