# Changing the Actions in EventHandler

I would like to be able to change which action specified events take depending on some condition. For example, I have established a SetterBar

SetterBar[Dynamic[setter], {Zoom, Pan}]


and created a graphic that I would like the left mouse button to cause to either zoom or pan, depending on what the value of setter is when the event occurs.

DynamicModule[{frac = 0, zoomval = 7*Pi/36, drag = {0, 0},
pt = CurrentValue[ImageSize], CurrentPosition = {1/2, 1/2},
panvalue = {0, 0}},
EventHandler[
Dynamic[Show[graphics,
ViewCenter -> {{1/2, 1/2,
1/2}, {x = CurrentPosition[[1]] + panvalue[[1]],
y = CurrentPosition[[2]] - panvalue[[2]]}},
ViewAngle -> (Which[drag[[2]] > 0,
zoomval = Min[Pi*0.7, zoomval + frac*(Pi - zoomval)],
drag[[2]] < 0,
zoomval = Max[zoomval - frac*(Pi - zoomval), 0.2],
drag[[2]] == 0, zoomval = zoomval]),
RotationAction -> "Clip"]], {{"MouseDown",
1} :> (a = CurrentValue[MousePosition]), {"MouseDragged",
1} :> {Which[
setter == Zoom, {b = CurrentValue[MousePosition], drag = b - a,
frac = 0.5 Norm[drag]/Norm[pt]},
setter == Pan, {b = CurrentValue[MousePosition], drag = b - a,
panvalue = {drag[[1]]/(pt[[1]]),
drag[[2]]/(pt[[2]])}}]}, {"MouseUp", 1} :> {frac = 0,
drag = {0, 0}, panvalue = {0, 0}, CurrentPosition[[1]] = x,
CurrentPosition[[2]] = y}}]]


This may be a little difficult to follow, but esentially I want the Which function to alter the action taken by the event "MouseDragged" depending on if setter is set to Zoom or Pan. Currently, everything works when the value is set to Zoom, but no action occurs upon setting the value to Pan.

Also, graphics is simply a red cylinder created for example.

graphics = Graphics3D[{Red, Cylinder[]}];

-
Manipulate[] can give you very similar functionality much more directly. Do you have some specific need to use "MouseDragged" or similar events? Also, best to show the minimum amount of code that demonstrates the problem. – Jagra Jul 19 '13 at 16:57
Sorry I showed so much, just wasn't sure what was wrong exactly. I don't really have to specifically use event handler, but I would ideally be able to rely only on the mouse. – Matt Jul 19 '13 at 17:53

As your code doesn't appear to run and presents so much to decipher before anyone could usefully help you with it, consider this simpler alternative:

Manipulate[
Graphics3D[{Red, Cylinder[]},
ImageSize -> iSize,
ViewAngle -> vAngle \[Degree]], {{iSize, 250}, 50, 500, 25}, {{vAngle, 40}, 50, 10, 1}]


A couple of screen shots of the output follows:

The Manipulate simply enables one to dynamically change the ImageSize of the Graphics3D object and its ViewAngle. I've set an initial value of the variable for ImageSize to 250 and range it from 50 to 500 in steps of 25.

For ViewAngle, I've specified it in degrees, set a default as 40 and allow it to range from 50 to 10 with a step of 1.

Take a look at howto/RotateZoomAndPanGraphics

Note that Mathematica typically enables 3D graphic output for rotating. You may have to do a bit more thinking to incorporate Pan.

This approach may not do everything you want, but it may give you a different and simpler way to think about what you want to do.

-
Thanks for the recommendation. It's a nice alternative and I think I can make pan work. However, this is for a display and I would prefer to not have to rely so much on sliders. Any alternatives you can think of? @Jagra – Matt Jul 19 '13 at 17:55
Check out Manipulate's options. It lets you use almost any type of control. Good luck. – Jagra Jul 19 '13 at 18:18
You helped a lot, and I managed to make something that I'm fairly content with. Do Manipulate and EventHandler not particularly play well together? @Jagra – Matt Jul 19 '13 at 18:18

Here is the minimal example what you are probably looking for.

Switching between zooming and rotating is handled in two places: If stops zooming unless zoom==True. PassEventsDown->!zoom prevents rotating when zooming is enabled.

DynamicModule[{y = .5, zoom},
EventHandler[
Column[{
Row[{Checkbox[Dynamic@zoom], "zoom"}],
Plot3D[Exp[-x^2 - y^2], {x, -4, 4}, {y, -4, 4}, PlotRange -> 1,
ViewAngle -> Dynamic@y, ImageSize -> 400]
}]
,
"MouseDown" :> If[zoom, init = y + Last@MousePosition["Graphics"]],
"MouseDragged" :> If[zoom, y = Clip[init-Last@MousePosition["Graphics"], {.2, 1}]],
PassEventsDown -> ! Dynamic@zoom
]
, Initialization :> (zoom = False)
]


-
+1 for most elegant solution within the OPs original idea. Also, very useful approach. Thx – Jagra Jul 22 '13 at 22:55
@Jagra your comment is far more rewarding than 3700rep :) Thanks! – Kuba Jul 22 '13 at 23:00

Using @Jagra's suggestion I was able to make a Manipulate function that was FAR neater than what I previously had (again, apologies for the unnecessarily long and messy code).

Manipulate[
Graphics3D[{Red, Cylinder[]}, ViewAngle -> Dynamic[vAngle \[Degree]],
ViewCenter -> {{1/2, 1/2, 1/2}, Dynamic[cen]}], {{vAngle, 30,
"Zoom"}, 90, 10, 1}, {{cen, {1/2, 1/2}, "Pan"}, {0, 0}, {1, 1}}]


While this isn't exactly what I was going for, I think it's definitely something that I can work with, and maybe tweak a little.

-
Your code as posted doesn't work. Not certain what you intend for Pan? Not certain you need an additional 'Dynamic' inside of the Manipulate. Maybe best to move this to the original post rather than as an answer. – Jagra Jul 19 '13 at 18:48
@Jagra What does the code do for you? I updated it, and it currently allows me to use the Zoom slider to change the angle of view and the two-dimensional Pan slider to change the location of the center of view. I originally tried without the additional Dynamic inside of Manipulate and the code only worked until I rotated the Graphic or used the traditional Shift and Ctrl methods to Zoom and Pan. Now that I have put the Dynamic inside, the code continuously works for me. – Matt Jul 19 '13 at 18:59
Ah! Much better. Works great. Looks good. Congratulations. – Jagra Jul 19 '13 at 19:13