+package vtk.rendering;
+
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.lang.reflect.Field;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper class used to implement all Mouse/Key Java listener and convert them
+ * into the vtkInteractor proper event.
+ *
+ * @authors Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2012
+ * Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public class vtkInteractorForwarder implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener {
+ final public static int MOUSE_BUTTON_1 = 1;
+ final public static int MOUSE_BUTTON_2 = 2;
+ final public static int MOUSE_BUTTON_3 = 4;
+ final public static int MOUSE_MODIFIER_SHIFT = 1;
+ final public static int MOUSE_MODIFIER_CTRL = 2;
+ final public static int MOUSE_MODIFIER_ALT = 4;
+
+ private int lastX;
+ private int lastY;
+ private int ctrlPressed;
+ private int shiftPressed;
+ private vtkComponent<?> component;
+ private double updateRate, updateRateRelease;
+ private double scaleFactor = 1;
+ private ScheduledExecutorService scheduler;
+ private Runnable eventTick;
+ private vtkEventInterceptor eventInterceptor;
+
+ public vtkInteractorForwarder(vtkComponent<?> component) {
+ this.component = component;
+ this.lastX = this.lastY = this.ctrlPressed = 0;
+ this.updateRate = 5.0;
+ this.updateRateRelease = 0.01;
+ this.scaleFactor = vtkInteractorForwarder.getDisplayScale();
+
+ this.eventTick = new Runnable() {
+
+ public void run() {
+ vtkInteractorForwarder.this.component.getVTKLock().lock();
+ vtkInteractorForwarder.this.component.getRenderWindowInteractor().TimerEvent();
+ vtkInteractorForwarder.this.component.getVTKLock().unlock();
+ }
+ };
+
+ // Schedule time events
+ this.scheduler = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ /**
+ * Provide a custom event interceptor
+ *
+ * @param eventInterceptor
+ */
+ public void setEventInterceptor(vtkEventInterceptor eventInterceptor) {
+ this.eventInterceptor = eventInterceptor;
+ }
+
+ /**
+ * @return the custom event interceptor if any otherwise return null
+ */
+ public vtkEventInterceptor getEventInterceptor() {
+ return eventInterceptor;
+ }
+
+ /**
+ * Method called by VTK to start a timer
+ */
+ public void StartTimer() {
+ this.scheduler.scheduleAtFixedRate(this.eventTick, 10, 10, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Method called by VTK to stop a timer
+ */
+ public void DestroyTimer() {
+ this.scheduler.shutdown();
+ }
+
+ /**
+ * Allow the user to change the update rate
+ *
+ * @param updateRate
+ * @param updateRateRelease
+ */
+ public void setUpdateRate(double updateRate, double updateRateRelease) {
+ this.updateRate = updateRate;
+ this.updateRateRelease = updateRateRelease;
+ }
+
+ /**
+ * @return the update rate that is currently used
+ */
+ public double getUpdateRate() {
+ return updateRate;
+ }
+
+ /**
+ * @return the update rate after release that is currently used
+ */
+ public double getUpdateRateRelease() {
+ return updateRateRelease;
+ }
+
+ public void mousePressed(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mousePressed(e)) {
+ return;
+ }
+
+ // Update scale factor if needed
+ this.scaleFactor = 1;
+ if (e.getComponent().getGraphicsConfiguration() != null) {
+ this.scaleFactor = vtkInteractorForwarder.getGraphicDeviceScale(e.getComponent().getGraphicsConfiguration().getDevice());
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRate);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ switch (e.getButton()) {
+ case MouseEvent.BUTTON3:
+ component.getRenderWindowInteractor().RightButtonPressEvent();
+ break;
+ case MouseEvent.BUTTON2:
+ component.getRenderWindowInteractor().MiddleButtonPressEvent();
+ break;
+ case MouseEvent.BUTTON1:
+ default:
+ component.getRenderWindowInteractor().LeftButtonPressEvent();
+ break;
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseReleased(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ switch (e.getButton()) {
+ case MouseEvent.BUTTON3:
+ component.getRenderWindowInteractor().RightButtonReleaseEvent();
+ break;
+ case MouseEvent.BUTTON2:
+ component.getRenderWindowInteractor().MiddleButtonReleaseEvent();
+ break;
+ case MouseEvent.BUTTON1:
+ default:
+ component.getRenderWindowInteractor().LeftButtonReleaseEvent();
+ break;
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseMoved(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseMoved(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseMoveEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseDragged(MouseEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseDragged(e)) {
+ return;
+ }
+
+ this.mouseMoved(e);
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseEntered(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().EnterEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseExited(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseExited(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().LeaveEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseClicked(e)) {
+ return;
+ }
+ }
+
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseWheelMoved(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ if (e.getWheelRotation() > 0) {
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseWheelBackwardEvent();
+ }
+ else if (e.getWheelRotation() < 0) {
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseWheelForwardEvent();
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void keyPressed(KeyEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyPressed(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ char keyChar = e.getKeyChar();
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, keyChar, 0, String.valueOf(keyChar));
+ component.getRenderWindowInteractor().KeyPressEvent();
+ component.getRenderWindowInteractor().CharEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void keyReleased(KeyEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyReleased(e)) {
+ return;
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyTyped(e)) {
+ return;
+ }
+ }
+
+ public static int getDisplayScale() {
+ GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+ return getGraphicDeviceScale(graphicsDevice);
+ }
+
+ public static int getGraphicDeviceScale(GraphicsDevice device) {
+ try {
+ Field field = device.getClass().getDeclaredField("scale");
+ if (field != null) {
+ field.setAccessible(true);
+ Object scale = field.get(device);
+ if (scale instanceof Integer) {
+ return ((Integer) scale).intValue();
+ }
+ System.out.println("Invalid scale type: " + scale);
+ }
+ } catch (Exception e) {
+ // Don't care, at least we tried.
+ }
+ return 1;
+ }
+}