Nasser
Nasser

Reputation: 13141

How to use a macro from inside a macro in the definition of Manipulate controls?

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

 ]

enter image description here

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.

enter image description here

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

 ]

enter image description here

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

Answers (2)

Mike Honeychurch
Mike Honeychurch

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

Leonid Shifrin
Leonid Shifrin

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

Related Questions