1

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.

Community
  • 1
  • 1
Nasser
  • 12,849
  • 6
  • 52
  • 104

2 Answers2

7

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.

Community
  • 1
  • 1
Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
1

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]}
   }]
 ]
Mike Honeychurch
  • 1,683
  • 10
  • 17
  • The point is that larger / more complex dynamic interfaces tend to contain lots of code duplication of type that is not easy to factor out, because, in particular, by doing so by conventional means we may bring some dynamic symbols out of scope. You can look at this post: http://stackoverflow.com/questions/7551647/how-to-define-part-of-a-manipulate-control-variable-definition-to-reduce-code-du, where such example was presented. The approach I advocated there was based on run-time code generation, so that the resulting `Manipulate` is exactly the same as the hand-written one.This new.. – Leonid Shifrin Dec 11 '11 at 22:06
  • ..question is a logical continuation of that discussion, dealing with cases when one wants to use nested macros. The OP presented what he considered a minimal example illustrating the issue (which is IMO a very right thing to do), which probably is why the question puzzled you. It will become more meaningful in the context of larger dynamic interfaces. – Leonid Shifrin Dec 11 '11 at 22:22
  • Fair enough as an exercise of how do you do this or that but if building complex interface was an objective then for starters I don't know why Manipulate would be used. In other words the need for things like this is probably due to the rigidity of Manipulate. Use DynamicModule and these problems disappear to a large extent. – Mike Honeychurch Dec 12 '11 at 03:20
  • @MikeHoneychurch, to publish a demonstration for WRI website, one is not allowed to build it using Dynamics directly but must use Manipulate[]. i.e. The demonstration CDF must all be inside Manipulate[]. – Nasser Dec 12 '11 at 03:26
  • Hi Nasser, yes I know that, so if publishing on the demonstrations website is your objective then self evidently you must use Manipulate. That objective is not stated in the question so I was responding to Leonid's reference to "larger dynamic interfaces." Wolfram's own larger dynamic interfaces, e.g. its CDF examples, do not use Manipulate. – Mike Honeychurch Dec 12 '11 at 03:32
  • @MikeHoneychurch, sorry that I forgot to mention that I must use Manipulate. Yes, CDF does support direct dynamics, no Manipulate is needed, but for the demo project, one still has to use Manipulate. Thanks – Nasser Dec 12 '11 at 04:08