6

Here is my issue : I am trying to write a bit of code that will draw a node in a given style. The styles are defined in a separate file. The name of the style is defined by a function that will create several variables with the same root name and a roman number to distinguish them. This is the design and it cannot be changed.

I would like to access the name of the style via a function called xaller that retrieve the content of the variable 'root+roman number' : it's working fine when the content is used to be displayed but not when the content is supposed to be used as the name of a style. I guess I need to indicate that the content retrieved designate a style for tikz, but I don't see how I could do that.

In the MWE, you will find a switch to what is currently working and what is not : I can access the content of the variable and use it as a style name when accessing the variable directly , but I can't use it when accessing via the xaller function. I tried a workaround with the function SetStyle which is supposed to attribute the name of the style to \monStyle , but it also doesn't work.

Any pointer would be helpful. Sorry if the code seems overkill, I minimized it the best I could.

\documentclass[10pt,twoside]{article}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[nomessages]{fp}
% graphics and color
\usepackage[usenames]{color}
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{matrix, shapes, patterns, fit, positioning}
\usepackage{etoolbox}

\begin{document}


%==================================================================================
%==================================================================================
%==================================================================================
% Define the xpl3 functions to attributes the variables
%\include{fonctionsMWE}
\ExplSyntaxOn

\cs_new:Npn \SetStyle #1
  { 
% clear new car si new seulement, se plaint que la variable existe deja
\tl_clear_new:N \l_my_tl

% convertit l argument en chiffre romain
\tl_set:Nn \l_my_tl { \int_to_Roman:n {#1} }

% concatene variableCouleurMatrice a ma var \l_my_tl par la gauche
\tl_put_left:Nn \l_my_tl { variableStyle  }

%show la variable
%\tl_use:N \l_my_tl
% use permet d executer la variable
\use:c { \tl_use:N \l_my_tl }
\let\monStyle\use:c { \tl_use:N \l_my_tl }
%\let\monStyle\variableStyleII
}
\ExplSyntaxOff

% Automation trial 7  : utilise la syntaxe expl3

\ExplSyntaxOn
\NewDocumentCommand{\DefinitionVariablesEnIndividuel}{O{variable}}
 {% pass control to an inner function
  % #1 is the "name part", default "variable"
  \aline_df:n { #1 }
 }

% define an integer variable
\int_new:N \l_aline_df_int

\cs_new_protected:Nn \aline_df:n
 {
  % the integer variable assigns the trailing roman number
  \int_zero:N \l_aline_df_int
  % start the recursion
  \__aline_df_peek:n { #1 }
 }
\cs_new_protected:Nn \__aline_df_peek:n
 {
  % check whether the next token is { (ignoring spaces)
  \peek_catcode_ignore_spaces:NT \c_group_begin_token
   {
    % if it is, increment the counter and call
    % \__aline_df_next:nn { #1 } { #2 }, where
    % { #2 } is the next braced group
    \int_incr:N \l_aline_df_int
    \__aline_df_next:nn { #1 }
   }
 }
\cs_new_protected:Nn \__aline_df_next:nn
 {
  % if the variable is already defined, clear it
  % otherwise create it
  \tl_clear_new:c { #1 \int_to_Roman:n { \l_aline_df_int } }
  \tl_clear_new:c { #1 ConstanteLongueur }
  % set the variable
  \tl_set:cn { #1 \int_to_Roman:n { \l_aline_df_int }}  { #2 }
  \tl_set:cx { #1 ConstanteLongueur } { \int_eval:n  { \l_aline_df_int } }

  % restart the recursion
  \__aline_df_peek:n { #1 }
 }

\ExplSyntaxOff



%==================================================================================
%==================================================================================

%==================================================================================
%==================================================================================
%\include{stylesMWE}
\tikzstyle{teteColonneNegatif} = [
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 3cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=black!100
    ]
\tikzset{
    teteColonne/.style={
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 5cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=red!100
    },
    teteColonne/.default=white
}


\newcommand{\xaller}[2]{%
      \uppercase\expandafter
     {\expandafter\def\expandafter\tmp\expandafter{\romannumeral #1}}%
      \csname #2\tmp\endcsname%
      %\csname variableStyle\tmp\endcsname%
}


%==================================================================================
%==================================================================================
%==================================================================================
% Define all the variables variableStyleN
\DefinitionVariablesEnIndividuel[variableStyle]{teteColonne}{teteColonneNegatif}{teteColonneNegatif}{teteColonne}{teteColonne}{teteColonne}{teteColonneNegatif}{teteColonne}

%==================================================================================
%==================================================================================
%==================================================================================

Wether the code is called from the variable or via the call of xaller, it is the same result :

xaller call : \xaller{1}{variableStyle}

direct variable : \variableStyleI

=======================================================


% Code to switch between what works (Generalization at false) and what doesn't (Generalization at true) 
\newif\ifGeneralization
\Generalizationtrue
\Generalizationfalse


% Use monStyle as a tmp variable for the node 
\ifGeneralization
    \let\monStyle\xaller{1}{variableStyle}
    %\SetStyle{1}
\else
    \let\monStyle\variableStyleI
\fi

Style used : \monStyle
\newline
\begin{tikzpicture}%
%\node[\variableStyleI](nom) at (1,10){\variableStyleI};
\node[\monStyle](nom) at (1,10){\monStyle};
\end{tikzpicture}


% Use monStyle as a tmp variable for the node 
\ifGeneralization
    \let\monStyle\xaller{2}{variableStyle}
\else
    \let\monStyle\variableStyleII
\fi
\let\monStyle\variableStyleII


Style used : \monStyle
\newline
\begin{tikzpicture}%
%\node[\variableStyleII](nom) at (1,10){\variableStyleII};
\node[\monStyle](nom) at (1,10){\monStyle};
\end{tikzpicture}
\end{document}
2
  • \tikzstyle is deprecated.
    – egreg
    Commented Apr 24, 2018 at 11:55
  • It looks like your \xaller is not expandable, check \xdef\monStyle{\xaller{1}{variableStyle}}. Probably some texpert will tell you why.
    – Kpym
    Commented Apr 24, 2018 at 12:18

2 Answers 2

5

For \xaller to be used here, it has to be expandable. So it can use neither \def nor \uppercase.

To make an expandable version (which is also more readable IMO), you can use expl3:

\ExplSyntaxOn
\cs_new:Npn \xaller #1 #2 {
  \use:c { #2 \int_to_Roman:n { #1 } }
}
\ExplSyntaxOff

The second problem is your usage of \let: The line

\let\monStyle\xaller{2}{variableStyle}

makes \monStyle an alias for \xaller, but \xaller is not expanded and {2}{variableStyle} are just output as regular text to the document. Later, when \monStyle is used, TeX tries to read the \xaller arguments and misses the number. This can be fixed by expanding \xaller three times (this needs a lot of \expandafters) or by by using \def instead:

\def\monStyle{\xaller{2}{variableStyle}}

This results in the working version

\documentclass[10pt,twoside]{article}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[nomessages]{fp}
% graphics and color
\usepackage[usenames]{color}
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{matrix, shapes, patterns, fit, positioning}
\usepackage{etoolbox}

\begin{document}


%==================================================================================
%==================================================================================
%==================================================================================
% Define the xpl3 functions to attributes the variables
%\include{fonctionsMWE}
\ExplSyntaxOn

\cs_new:Npn \SetStyle #1
  { 
% clear new car si new seulement, se plaint que la variable existe deja
\tl_clear_new:N \l_my_tl

% convertit l argument en chiffre romain
\tl_set:Nn \l_my_tl { \int_to_Roman:n {#1} }

% concatene variableCouleurMatrice a ma var \l_my_tl par la gauche
\tl_put_left:Nn \l_my_tl { variableStyle  }

%show la variable
%\tl_use:N \l_my_tl
% use permet d executer la variable
\use:c { \tl_use:N \l_my_tl }
\let\monStyle\use:c { \tl_use:N \l_my_tl }
%\let\monStyle\variableStyleII
}
\ExplSyntaxOff

% Automation trial 7  : utilise la syntaxe expl3

\ExplSyntaxOn
\NewDocumentCommand{\DefinitionVariablesEnIndividuel}{O{variable}}
 {% pass control to an inner function
  % #1 is the "name part", default "variable"
  \aline_df:n { #1 }
 }

% define an integer variable
\int_new:N \l_aline_df_int

\cs_new_protected:Nn \aline_df:n
 {
  % the integer variable assigns the trailing roman number
  \int_zero:N \l_aline_df_int
  % start the recursion
  \__aline_df_peek:n { #1 }
 }
\cs_new_protected:Nn \__aline_df_peek:n
 {
  % check whether the next token is { (ignoring spaces)
  \peek_catcode_ignore_spaces:NT \c_group_begin_token
   {
    % if it is, increment the counter and call
    % \__aline_df_next:nn { #1 } { #2 }, where
    % { #2 } is the next braced group
    \int_incr:N \l_aline_df_int
    \__aline_df_next:nn { #1 }
   }
 }
\cs_new_protected:Nn \__aline_df_next:nn
 {
  % if the variable is already defined, clear it
  % otherwise create it
  \tl_clear_new:c { #1 \int_to_Roman:n { \l_aline_df_int } }
  \tl_clear_new:c { #1 ConstanteLongueur }
  % set the variable
  \tl_set:cn { #1 \int_to_Roman:n { \l_aline_df_int }}  { #2 }
  \tl_set:cx { #1 ConstanteLongueur } { \int_eval:n  { \l_aline_df_int } }

  % restart the recursion
  \__aline_df_peek:n { #1 }
 }

\ExplSyntaxOff



%==================================================================================
%==================================================================================

%==================================================================================
%==================================================================================
%\include{stylesMWE}
\tikzstyle{teteColonneNegatif} = [
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 3cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=black!100
    ]
\tikzset{
    teteColonne/.style={
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 5cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=red!100
    },
    teteColonne/.default=white
}

\ExplSyntaxOn
\cs_new:Npn \xaller #1 #2 {
  \use:c { #2 \int_to_Roman:n { #1 } }
}
\ExplSyntaxOff


%==================================================================================
%==================================================================================
%==================================================================================
% Define all the variables variableStyleN
\DefinitionVariablesEnIndividuel[variableStyle]{teteColonne}{teteColonneNegatif}{teteColonneNegatif}{teteColonne}{teteColonne}{teteColonne}{teteColonneNegatif}{teteColonne}

%==================================================================================
%==================================================================================
%==================================================================================

Wether the code is called from the variable or via the call of xaller, it is the same result :

xaller call : \xaller{1}{variableStyle}

direct variable : \variableStyleI

=======================================================


% Code to switch between what works (Generalization at false) and what doesn't (Generalization at true) 
\newif\ifGeneralization
\Generalizationtrue
%\Generalizationfalse


% Use monStyle as a tmp variable for the node 
\ifGeneralization
    \def\monStyle{\xaller{1}{variableStyle}}
    %\SetStyle{1}
\else
    \let\monStyle\variableStyleI
\fi

Style used : \monStyle
\newline
\begin{tikzpicture}%
%\node[\variableStyleI](nom) at (1,10){\variableStyleI};
\node[\monStyle](nom) at (1,10){\monStyle};
\end{tikzpicture}


% Use monStyle as a tmp variable for the node 
\ifGeneralization
    \def\monStyle{\xaller{2}{variableStyle}}
\else
    \let\monStyle\variableStyleII
\fi
\let\monStyle\variableStyleII


Style used : \monStyle
\newline
\begin{tikzpicture}%
%\node[\variableStyleII](nom) at (1,10){\variableStyleII};
\node[\monStyle](nom) at (1,10){\monStyle};
\end{tikzpicture}
\end{document}
1
  • Thx a lot, it works perfectly !!!
    – Aline
    Commented Apr 24, 2018 at 13:16
3

Your mix of old and new style programming is the problem, plus the misunderstanding of how \let works.

\documentclass[10pt,twoside]{article}
\usepackage{xparse}
\usepackage[usenames]{xcolor}

\usepackage{tikz}
\usetikzlibrary{matrix, shapes, patterns, fit, positioning}

\begin{document}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\xaller}{mm}
 {
  \use:c { #2 \int_to_Roman:n { #1 } }
 }

\NewDocumentCommand \SetStyle { m }
 {
  \cs_set:Npx \monStyle { \xaller{#1}{variableStyle} }
 }

\NewDocumentCommand{\DefinitionVariablesEnIndividuel}{O{variable}}
 {% pass control to an inner function
  % #1 is the "name part", default "variable"
  \aline_df:n { #1 }
 }

% define an integer variable
\int_new:N \l_aline_df_int

\cs_new_protected:Nn \aline_df:n
 {
  % the integer variable assigns the trailing roman number
  \int_zero:N \l_aline_df_int
  % start the recursion
  \__aline_df_peek:n { #1 }
 }
\cs_new_protected:Nn \__aline_df_peek:n
 {
  % check whether the next token is { (ignoring spaces)
  \peek_catcode_ignore_spaces:NT \c_group_begin_token
   {
    % if it is, increment the counter and call
    % \__aline_df_next:nn { #1 } { #2 }, where
    % { #2 } is the next braced group
    \int_incr:N \l_aline_df_int
    \__aline_df_next:nn { #1 }
   }
 }
\cs_new_protected:Nn \__aline_df_next:nn
 {
  % if the variable is already defined, clear it
  % otherwise create it
  \tl_clear_new:c { #1 \int_to_Roman:n { \l_aline_df_int } }
  \tl_clear_new:c { #1 ConstanteLongueur }
  % set the variable
  \tl_set:cn { #1 \int_to_Roman:n { \l_aline_df_int }}  { #2 }
  \tl_set:cx { #1 ConstanteLongueur } { \int_eval:n  { \l_aline_df_int } }

  % restart the recursion
  \__aline_df_peek:n { #1 }
 }
\ExplSyntaxOff

\tikzset{
  teteColonneNegatif/.style = {
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 3cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=black!100
  },
  teteColonne/.style={
    text centered,
    text=white, font=\bfseries,
    minimum height=1em,
    text depth=0.5em, text height=1em, 
    text width = 5cm,
    rectangle, fill=none, draw=none, rounded corners,
    fill=red!100
  },
  teteColonne/.default=white,
}


% Define all the variables variableStyleN
\DefinitionVariablesEnIndividuel[variableStyle]
  {teteColonne}
  {teteColonneNegatif}
  {teteColonneNegatif}
  {teteColonne}
  {teteColonne}
  {teteColonne}
  {teteColonneNegatif}
  {teteColonne}

\SetStyle{1}

Style used : \verb|\monStyle|

\begin{tikzpicture}
\node[\monStyle](nom) at (1,10){\monStyle};
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\foreach \i in {1,...,8} {
  \node[\xaller{\i}{variableStyle},text width=9cm](nom) at (1,10+\i){\xaller{\i}{variableStyle}};
}
\end{tikzpicture}

\end{document}

enter image description here

You must log in to answer this question.

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