Reputation: 13141
I am using Leonid's macro method (see here) to help me manage the control variables layout of Manipulate
.
But I found that from within a macro, I am not able to use another macro defined elsewhere. So I am wondering if there is a way to use a macro from within another macro?
To explain the question, I will first show a very simple Manipulate using a one level macro, then I will show the problem, by trying to use a macro from within another.
Manipulate[Text["ok"],
Evaluate@With[{
x = Function[{}, (*----> macro x *)
TabView[{
"x" -> "working on x"
}], HoldAll
],
y = Function[{}, (*----> macro y *)
TabView[{
"y" -> "working on y"
}], HoldAll
]
},(*WITH*)
(* now use the above macros *)
Grid[{
{SetterBar[Dynamic[choice], {1, 2}]},
{Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
}]
],
{{choice, 1}, None},
ContentSize -> 300
]
Now add a macro for a checkbox, and then try to use it from inside the 'x' macro above:
Manipulate[Text["ok"],
Evaluate@With[{
checkBox = Function[{}, Checkbox[Dynamic[c]], HoldAll],
x = Function[{},
TabView[{
"x" -> checkBox[] (*=====> DOES NOT WORK, did not bind *)
}], HoldAll
],
y = Function[{},
TabView[{
"y" -> "working on y"
}], HoldAll
]
},(*WITH*)
Grid[{
{SetterBar[Dynamic[choice], {1, 2}]},
{Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
}]
],
{{choice, 1}, None},
{{c, True}, None},
ContentSize -> 300
]
We see it did not work. The 'x' macro did not 'see' the checkbox macro.
But if I add the code for the checkbox directly inside the 'x' macro, it will of course work:
Manipulate[Text["ok"],
Evaluate@With[{
x = Function[{},
TabView[{
"x" -> Checkbox[Dynamic[c]] (* add the definition directly *)
}], HoldAll
],
y = Function[{},
TabView[{
"y" -> "working on y"
}], HoldAll
]
},(*WITH*)
Grid[{
{SetterBar[Dynamic[choice], {1, 2}]},
{Dynamic[Which[choice == 1, x[], choice == 2, y[]] ]}
}]
],
{{choice, 1}, None},
{{c, True}, None},
ContentSize -> 300
]
So, the question is: Is it possible to use the checkbox macro above from inside the 'x' macro?
To make it is easier, I am NOT passing any arguments to the macros. I am simply using a macro as a 'short hand' name for a piece of larger code fragment (the control variable definition) as shown above.
This is only to make it easier for me to layout the UI by moving only the macro name around, instead of moving the larger piece of code which the macro defines. Since there is no GUI builder for Manipulate, this method helps when one has lots of controls to manage.
Upvotes: 1
Views: 489
Reputation: 1683
I'm new to this site so what you are trying to do may have different objectives but is there any reason why you can't just code this directly?
DynamicModule[{choice = 1, c = False},
Grid[{
{SetterBar[Dynamic[choice], {1, 2}]},
{Dynamic[
Which[choice == 1, TabView[{"x" -> Checkbox[Dynamic[c]]}],
choice == 2, TabView[{"y" -> "working on y"}]]]},
{Dynamic[choice], Dynamic[c]}
}]
]
Upvotes: 1
Reputation: 22579
This is because you need a nested With
in this case. You can not use the declaration of one variable in another one in the same declaration list in With
. Here is the simplified version of your problem:
In[3]:= With[{a=b,c=f[a]},g[c]]
Out[3]= g[f[a]]
This is what you need instead:
In[5]:=
With[{a=b},
With[{c=f[a]},g[c]]]
Out[5]= g[f[b]]
in your case, checkBox
plays the role of a
, and x
plays the role of c
.
The topic of how to make a version of With
that would allow such consecutive bindings, was discussed several times on Mathgroup and here at SO. Here is my implementation of such a construct:
ClearAll[LetL];
SetAttributes[LetL, HoldAll];
LetL /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[LetL[{__}, _]]] :=
Block[{With}, Attributes[With] = {HoldAll};
lhs := Evaluate[rhs]];
LetL[{}, expr_] := expr;
LetL[{head_}, expr_] := With[{head}, expr];
LetL[{head_, tail__}, expr_] :=
Block[{With}, Attributes[With] = {HoldAll};
With[{head}, Evaluate[LetL[{tail}, expr]]]];
If you are willing to use it, all you have to do is to change With
to LetL
in your code.
Upvotes: 7