# Dynamic Linkage of LocatorPane and InputField

How do I get the InputField to coordinate with the LocatorPane so that a change in each control changes the other to be in agreement? It would be nice if the function was self-contained and was dynamically linked to a second similar control where the variable is radians. The angle control is based on this (see Applications). Related links do not address or solve this particular issue; links such as this this, and this

 fDeg[Dynamic[angleDeg_]] :=
DynamicModule[{p, angleRad, angleCalc, dtr = Degree},

angleCalc[newp_,
angleRad + ArcCos[newp.oldp] Sign[Cross[newp].(newp - oldp)];
f[angleDeg];

LocatorPane[Dynamic[p, (angleCalc @@ Normalize /@ {#, p}) &],
Dynamic@Show[
Arrow[Dynamic[{{0, 0}, p}]]}, ImageSize -> Tiny],
Graphics[{Dynamic[{Text[
NumberForm[angleDeg, {3, 2}], {0, 0}]}]}]],
Appearance -> None]];

Column[{
"Degrees:",
FieldSize -> 6]
}, Alignment -> Center]


Consider the following refactoring of your code

First, the locator pane is used to set a point location constrained on a circle with unit radius (this part borrowed heavily from an example in the documentation for LocatorPane). A degree value is then calculated from the coordinates of tha tpoint.

Secondly, the input field is used to read in a degree value, which is then used to update the position of the dynamic point pt using the second argument of Dynamic.

DynamicModule[
{pt = {0, 1.}},
Column[{
"Degrees:", Dynamic[(ArcTan @@ pt)/Degree],
LocatorPane[
Dynamic[pt],
Graphics[{
Circle[],
PointSize[Large],
Dynamic[Arrow[{{0, 0}, pt/Norm[pt]}]]
}],
Appearance -> None
],
InputField[
Dynamic[(ArcTan @@ pt)/Degree, (pt = N@{Cos[#1 Degree], Sin[#1 Degree]}) &],
FieldSize -> Tiny
]
}, Alignment -> Center
]
]


This keeps both fields in sync with each other:

• MarcoB. This is nice. But I was hoping for a self-contained function where only aDeg is passed. One reason for this is to allow aDeg to be altered elsewhere by some process such as a simulation of an automated flight control system. The controls (LocatorPane and InputField) would change accordingly. But the simulation could be interrupted by the user by means of the controls, and a new value input by the field or the dial. Any thoughts? – kmutiny Mar 11 '19 at 2:25

An alternative way to use ExperimentalAngularSlider is to use a single dynamic variable and limit the angles to the range 0 to 360 using {0,360} as the second argument of AngularSlider:

DynamicModule[{z = 120},
Column[{ExperimentalAngularSlider[Dynamic[z], {0, 360},
ExperimentalBoundaryAction -> "Clip"],
InputField[Dynamic[z], ImageSize -> {100, 24}, BaseStyle -> 16]},
Alignment -> Center]]


To display angles in radians and degrees and allow the slider to move around the clock:

DynamicModule[{z = 120},
Panel @ Column[{Style["Degree", 16],
Overlay[{ExperimentalAngularSlider[Dynamic[z,(z = Round[#, 1]) &], {0, 360},
ExperimentalBoundaryAction -> "Wrap", ImageSize -> 200],
Graphics[{Text[Framed[Style[Dynamic[Round[z,1]] °, 16], FrameStyle -> None],
Scaled @ {3/4, 4/10}, {-1, 1}],
Text[Framed[Style[Dynamic[Round[z Degree, Pi/2^7] ], 16], FrameStyle -> None],
Scaled @ {3/4, 4/10}, {-1, -1}]}]}, All, 1],
InputField[Dynamic[z, (z = Round[#, 1]) &], ImageSize -> {100, 24}, BaseStyle -> 16]},
Alignment -> Center]]


If you want to play with various options of ExperimentalAngularSlider you can use

NotebookToolsAngularSliderTest[]


Here is a simplified demo linking an InputField[] with ExperimentalAngularSlider[]:

DynamicModule[{x = 0., u = 0.},
Column[{ExperimentalAngularSlider[Dynamic[x, (x = #; u = x/Degree) &]],
InputField[Dynamic[u, (u = #; x = u Degree) &], Number]}]]


Clicking on the AngularSlider[] updates the value in the InputField[], and entering a (degree) value in the InputField[] moves the slider to the specified angle.

I think the following code solves the issue, though I’m not sure exactly why it works but the other didn't. Note that the function is self-contained, and that the InputField should be placeable in a separate part of an application. Also note the added features. The next step would be to make a function for radians and link the 2 controls.

 DynamicModule[{gSquare, dtr, rtd, AngularControlDegFnc01,

{
dtrH = Pi/180., rtdH = 180./Pi,
Pi2H = 2*Pi, icrH = .25, thH = 0.01, athH = 0.017,
c1H = RGBColor[.8, .5, .5], c2H = RGBColor[.5, .5, .8],
pH, pCalcH, aCalcH, cCalcH, mCalcH, wCalcH, rCalcH
},

wCalcH[] := {icrH*pCalcH[], pCalcH[]};
cCalcH[] := If[Sign[aRadH] == -1, Return[c1H], Return[c2H]];
mCalcH[] := Block[{},
aCalcH[newpArg_, oldpArg_] := Block[{},
Sign[Cross[newpArg].(newpArg - oldpArg)];
mCalcH[];
pCalcH[]];

rCalcH[];
pCalcH[];

LocatorPane[Dynamic[pH, (aCalcH @@ Normalize /@ {#, pH}) &],
Dynamic[ShowDeg = Show[{
Graphics[{cCalcH[], Disk[{0, 0}, 1, {0, rCalcH[]}]}],
Graphics[{Black, Thickness[thH], Line[{{0, 0}, {1, 0}}]}],
Graphics[{GrayLevel[.8], Disk[{0, 0}, icrH]}],
Graphics[{Thickness[thH], Circle[{0, 0}, icrH]}],
Graphics[{Black, Thickness[1.5*thH], Circle[]}],
Arrow[wCalcH[]]}],
Graphics[{Dynamic[{Text[
NumberForm[Round[aDegArg, 0.01], {3, 1}], {0, 0}]}]}]},
ImageSize -> 150]

], Appearance -> None]
];

gSquare =
Graphics[{Gray, Thick,
Line[1.4*{{-1, -1}, {-1, +1}, {+1, +1}, {+1, -1}, {-1, -1}}]}];
dtr = Pi/180.;
rtd = 180./Pi;
`