9

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

DavidC
  • 16,724
  • 1
  • 42
  • 94
  • 6
    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." – Sjoerd C. de Vries Nov 04 '12 at 18:43
  • @SjoerdC.deVries Can you include a link? My last question would also benefit from it – Dr. belisarius Nov 04 '12 at 18:47
  • @belisarius It's slightly below http://wolfram.com/xid/0fz3xp8d3e93ro (the Locator section, between In[36] and In[37]). – Sjoerd C. de Vries Nov 04 '12 at 18:50
  • @SjoerdC.deVries Thanks, going to update my question – Dr. belisarius Nov 04 '12 at 18:52
  • @Sjoerd: I see. But neither of the locators I'm using is multipoint. – DavidC Nov 04 '12 at 19:25
  • Indeed, that's why I wrote that this does not correspond exactly to your situation. I assume that all individual Locator variables are internally merged into a single multipoint list and that could be the reason that another multipoint list is not welcome here. If there is one internal point list then I'd guess there is also only one internal Enabled state. But this is all guesswork based on the above mentioned doc snippet. – Sjoerd C. de Vries Nov 04 '12 at 21:05

2 Answers2

7

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.

WReach
  • 68,832
  • 4
  • 164
  • 269
  • 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. – DavidC Nov 05 '12 at 17:17
1

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

István Zachar
  • 47,032
  • 20
  • 143
  • 291
  • 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.) – DavidC Nov 05 '12 at 17:23
  • @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. – István Zachar Nov 05 '12 at 17:59