9
$\begingroup$

I am wondering why the Enabled setting for the first locator (point1) overrides the Enabled setting for the second locator (point2). Any ideas?

Manipulate[
 Graphics[{ {{Arrow[{{0, 0}, point1}]}}, {{Arrow[{{0, 0}, 
   point2}]}}},
  Axes -> True, PlotRange -> {{-4, 8}, {-4, 8}}],
{{point1, {-1, 3}}, {-4, -4}, {8, 8}, {.1, .1}, Locator, Enabled -> False},
{{point2, {5, -2}}, {-3, -3}, {6, 6}, {.1, .1}, Locator, Enabled -> True}]

One of the locators should be enabled; the other should be disabled. However, as the picture shows, they are both disabled.

I realize I could work around this by using LocatorPane, but I'm curious why this doesn't work for individual locators. Am I overlooking something or is this a bug?

locators

$\endgroup$
6
  • 6
    $\begingroup$ I assume all locators are swept together internally and the first Enabled encountered determines the state of all. There is some hint (it's not precisely your situation) about the internal difficulties involved in combining multiple locators in the documentation: "Due to internal limitations, it is not possible to combine individual Locator variables with a variable that is a list of multiple Locator variables: you can have only one multipoint Locator variable in a Manipulate." $\endgroup$ Nov 4, 2012 at 18:43
  • $\begingroup$ @SjoerdC.deVries Can you include a link? My last question would also benefit from it $\endgroup$ Nov 4, 2012 at 18:47
  • $\begingroup$ @belisarius It's slightly below wolfram.com/xid/0fz3xp8d3e93ro (the Locator section, between In[36] and In[37]). $\endgroup$ Nov 4, 2012 at 18:50
  • $\begingroup$ @SjoerdC.deVries Thanks, going to update my question $\endgroup$ Nov 4, 2012 at 18:52
  • $\begingroup$ @Sjoerd: I see. But neither of the locators I'm using is multipoint. $\endgroup$
    – DavidC
    Nov 4, 2012 at 19:25

2 Answers 2

7
$\begingroup$

As surmised by @Sjoerd in the question's comments, Manipulate combines all locators into a single LocatorPaneBox. We can see this if we inspect the boxes generated by the Manipulate expression:

PaneBox[PanelBox[DynamicWrapperBox[PaneSelectorBox[{True->GridBox[{{
...
LocatorPaneBox[
  Dynamic[{$CellContext`point1$$,$CellContext`point2$$}],
  ...
  Enabled->False,Enabled->True]
...
FrameMargins->{{5,5},{5,5}}],ImageMargins->0,BaselinePosition->Automatic]

This excerpted snippet shows us two things. First, we can see the single LocatorPaneBox that references both points. Second, we can see that the Enabled option is specified twice. As usual, the first instance takes precedence over the second with the result that both locators are disabled. This second point feels like a bug.

To work around this problem is tricky. We could try to use an explicit LocatorPane, but that does not allow us to specify independent regions or enablement states for each locator. If we try to use two LocatorPane expressions, we run into problems when the outer pane is disabled -- events do not get sent down to the inner pane. It is possible to work around this using elaborate EventHandler interactions, but it is not pretty. I suspect that these problems are what led to the present restrictions in the Manipulate implementation.

In this particular case, a simpler solution is to abandon LocatorPane altogether and to include explicit Locator directives instead:

clip[pt:{x_, y_}, {xMin_, yMin_}, {xMax_, yMax_}, {xStep_, yStep_}] :=
  {Round[Clip[x, {xMin, xMax}], xStep], Round[Clip[y, {yMin, yMax}], yStep]}

Manipulate[
  Graphics[
    { Arrow[{{0, 0}, point1}]
    , Arrow[{{0, 0}, point2}]
    , Locator[Dynamic[point1,(point1=clip[#, {-4, -4}, {8, 8}, {.1, .1}])&], Enabled->False]
    , Locator[Dynamic[point2,(point2=clip[#, {-3, -3}, {6, 6}, {.1, .1}])&], Enabled->True]
    }
  , Axes -> True, PlotRange -> {{-4, 8}, {-4, 8}}
  ]
, {{point1, {-1, 3}}, None}
, {{point2, {5, -2}}, None}
]

Unfortunately, this means that we must implement the locator region constraints ourselves since Locator does not offer that service (LocatorRegion only provides crude clipping). However, this is easier than the event-handling gymnastics that would otherwise be required for LocatorPane.

$\endgroup$
1
  • $\begingroup$ Very nice! Using this method, and checkboxes, it is also possible to control both the Enabled state and visibility (i.e Appearance) of each locator independently. $\endgroup$
    – DavidC
    Nov 5, 2012 at 17:17
1
$\begingroup$

This is just a possible workaround to overcome the issue (WReach has nicely debunked it) by simulating a Manipulate interface. As always, start by writing a DynamicModule object that is then wrapped in a dummy Manipulate wrapper:

Manipulate@DynamicModule[{point1 = {-1, 3}, point2 = {5, -2}},
  Graphics[{
    Dynamic@Arrow[{{0, 0}, point1}],
    Dynamic@Arrow[{{0, 0}, point2}],
    Locator[Dynamic[point1, (point1 = Clip[#, {-4, 8}]) &], Enabled -> False],
    Locator[Dynamic[point2, (point2 = Clip[#, {-3, 6}]) &], Enabled -> True]
    }, Axes -> True, PlotRange -> {{-4, 8}, {-4, 8}}]
  ]

Mathematica graphics

$\endgroup$
2
  • $\begingroup$ What advantages are gained by using Dynamic Module? Also, in what sense is Manipulate being used as a dummy wrapper. Do you mean that no interactive functionality is actually required? (Actually, in the full implementation, there are 8 or so controls that are needed. Most are checkboxes, including those to Enable/Disable the locators individually.) $\endgroup$
    – DavidC
    Nov 5, 2012 at 17:23
  • $\begingroup$ @David The DynamicModule works perfectly without the Manipulate. It is dynamic in itself and can hold any number of Locators or LocatorPanes, so the Manipulate is only there to provide 1) the familiar paneled look-and-feel (e.g. the + button in the top right), and 2) the somewhat necessary wrapper for deploying to CDF. $\endgroup$ Nov 5, 2012 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.