10

I'm implementing a two-sided slider to be able to set upper and lower bound in just one slider:

enter image description here

The problem is that it can get stuck when both locators are at the far left:

enter image description here

And I'm unable to grab the blue locator.

SetAttributes[TwoSidedSlider, HoldAll];
TwoSidedSlider[sliderMin_, sliderMax_, var1_, var2_, 
  maxIsInfinity_: False] := DynamicModule[
  {pt = {{var1, 0}, {If[var2 == Infinity, sliderMax, var2], 0}}},
  LocatorPane[
   Dynamic[pt,
    ((* Update while dragging \*)
      pt = #1;
      var1 = #1[[1, 1]];
      var2 = 
       If[maxIsInfinity && #1[[2, 1]] == sliderMax, 
        Infinity, #1[[2, 1]]];
      ) &
    ],
   Graphics[{
     Gray, Line[{{sliderMin, 0}, {Dynamic[pt[[1, 1]]], 0}}],(* min to lower \*)
     Black, 
     Line[{{Dynamic[pt[[1, 1]]], 0}, {Dynamic[pt[[2, 1]]], 0}}], (* lower to upper \*)
     Gray, 
     Line[{{Dynamic[pt[[2, 1]]], 0}, {sliderMax, 0}}] (* upper to max \*)
     }, AspectRatio -> 1/5],
   { (* Locator Region and stepsize \*)
    {{sliderMin, 0},
     {Dynamic[pt[[2, 1]]], 0}, {1, 1}},
    {{Dynamic[pt[[1, 1]]], 0},
     {sliderMax, 0}, {1, 1}}
    }
   , Appearance -> {Style["[", Red, Larger, Bold], 
     Style["]", Blue, Larger, Bold]}]]

It is used something like this:

lower = 0; upper = Infinity;
{{Dynamic[lower], TwoSidedSlider[0, 5000, lower, upper, True], 
   Dynamic[upper]}} // TableForm

Any tips on how to get a two-sided slider or what causes this one to get stuck?

István Zachar
  • 47,032
  • 20
  • 143
  • 291
ssch
  • 16,590
  • 2
  • 53
  • 88

2 Answers2

4

Use:

pt = Clip[#1\[Transpose]*{1, 0}, {sliderMin, sliderMax}]\[Transpose];

as the update function, and remove the min-max restrictions from the LocatorPane (3rd argument). Also, when you update pt based on #1, you should use pt instead of #1 when you update var1 and var2:

SetAttributes[TwoSidedSlider, HoldAll];
TwoSidedSlider[sliderMin_, sliderMax_, var1_, var2_, 
  maxIsInfinity_: False] := DynamicModule[
  {pt = {{var1, 0}, {If[var2 == Infinity, sliderMax, var2], 0}}},
  LocatorPane[Dynamic[pt, (
      pt = 
       Clip[#1\[Transpose]*{1, 0}, {sliderMin, sliderMax}]\[Transpose];
      var1 = pt[[1, 1]];
      var2 = 
       If[maxIsInfinity && pt[[2, 1]] == sliderMax, Infinity, 
        pt[[2, 1]]];
      ) &],
   Graphics[{Gray,
     Line[{{sliderMin, 0}, {Dynamic[pt[[1, 1]]], 0}}],
      Black, 
     Line[{{Dynamic[pt[[1, 1]]], 0}, {Dynamic[pt[[2, 1]]], 0}}],
      Gray, Line[{{Dynamic[pt[[2, 1]]], 0}, {sliderMax, 0}}]}, 
    AspectRatio -> 1/5],
   (*{{{sliderMin,0},{var1,0},{1,1}},{{0,0},{sliderMax,0},{1,1}}},*)
   Appearance -> {Style["[", Red, Larger, Bold], 
     Style["]", Blue, Larger, Bold]}]]

lower = 0; upper = Infinity;
{{Dynamic[lower], TwoSidedSlider[0, 5000, lower, upper, True], 
   Dynamic[upper]}} // TableForm
István Zachar
  • 47,032
  • 20
  • 143
  • 291
4

The problem is that when the sliders have the same value, Dynamic chooses the wrong to move when you click near it. You could make the sliders have a small gap between them and it works as expected

SetAttributes[TwoSidedSlider, HoldAll];
TwoSidedSlider[sliderMin_, sliderMax_, var1_, var2_, 
  maxIsInfinity_: False] := 
 DynamicModule[{pt = {{var1, 
      0}, {If[var2 == Infinity, sliderMax, var2], 0}}}, 
  LocatorPane[Dynamic[pt, ((*Update while dragging *) pt = #1;
      var1 = #1[[1, 1]];
      var2 = 
       If[maxIsInfinity && #1[[2, 1]] == sliderMax, 
        Infinity, #1[[2, 1]]];) &], 
   Graphics[{Gray, 
     Line[{{sliderMin, 0}, {Dynamic[pt[[1, 1]]], 0}}],(*min to lower *) 
     Black, Line[{{Dynamic[pt[[1, 1]]], 0}, {Dynamic[pt[[2, 1]]], 
        0}}],(*lower to upper *) Gray, 
     Line[{{Dynamic[pt[[2, 1]]], 0}, {sliderMax, 0}}]
      (*upper to max *)}, AspectRatio -> 1/5], {
     (*Locator Region and stepsize *) {{sliderMin, 
      0}, {Dynamic[pt[[2, 1]] - 1], 0}, {1, 
      1}}, {{Dynamic[pt[[1, 1]] + 1], 0}, {sliderMax, 0}, {1, 1}}}, 
   Appearance -> {Style["[", Red, Larger, Bold], 
     Style["]", Blue, Larger, Bold]}]]

Note the change in the last argument to LocatorPane.

halirutan
  • 112,764
  • 7
  • 263
  • 474