Refactoring.
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / gui / humaninput / UserInputTracker.java
index bb14bd3..3060691 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Sixth 3D engine. Copyright ©2012-2016, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
+ * Sixth 3D engine. Copyright ©2012-2018, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 3 of the GNU Lesser General Public License
@@ -11,9 +11,8 @@ package eu.svjatoslav.sixth.e3d.gui.humaninput;
 
 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
 import eu.svjatoslav.sixth.e3d.gui.Avatar;
-import eu.svjatoslav.sixth.e3d.gui.View;
-import eu.svjatoslav.sixth.e3d.gui.ViewContext;
-import eu.svjatoslav.sixth.e3d.gui.ViewUpdateListener;
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener;
 
 import javax.swing.*;
 import java.awt.event.*;
@@ -22,8 +21,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class UserInputTracker
-        implements MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewUpdateListener {
+public class UserInputTracker implements
+        MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewRenderListener {
 
     /**
      * <pre>
@@ -36,36 +35,34 @@ public class UserInputTracker
     private final Map<Integer, Long> pressedKeysToPressedTimeMap = new HashMap<>();
     private final List<MouseClick> detectedMouseClicks = new ArrayList<>();
     private final List<KeyEvent> detectedKeyEvents = new ArrayList<>();
-    public int wheelMovedDirection = 0;
-    Point2D mouseDraggedDirection = new Point2D();
-    Point2D oldMouseCoordinatesWhenDragging;
-    ViewContext viewContext;
-    Point2D currentMouseLocation;
-    boolean mouseMoved;
+    private int wheelMovedDirection = 0;
+    private Point2D mouseDraggedDirection = new Point2D();
+    private Point2D oldMouseCoordinatesWhenDragging;
+    private ViewPanel viewPanel;
+    private Point2D currentMouseLocation;
+    private boolean mouseMoved;
     private boolean mouseWithinWindow = false;
 
-    public UserInputTracker(final ViewContext viewContext) {
-        this.viewContext = viewContext;
+    public UserInputTracker(final ViewPanel viewPanel) {
+        this.viewPanel = viewPanel;
+        bind(viewPanel);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public boolean beforeViewUpdate(final ViewContext viewContext, final int millisecondsSinceLastFrame) {
+    public boolean beforeRender(final ViewPanel viewPanel, final int millisecondsSinceLastFrame) {
 
-        boolean viewUpdateNeeded = handleDetectedMouseClicks(viewContext.getView());
-
-        viewUpdateNeeded |= handleDetectedKeyEvents();
-
-        viewContext.getKeyboardFocusTracker().getCurrentFocusOwner().beforeViewUpdate(viewContext,
-                millisecondsSinceLastFrame);
-        viewUpdateNeeded |= trackMouse();
+        boolean viewUpdateNeeded = handleKeyboardEvents();
+        viewUpdateNeeded |= handleMouseClicksAndHover(viewPanel);
+        viewUpdateNeeded |= handleMouseDragging();
+        viewUpdateNeeded |= handleMouseVerticalScrolling();
 
         return viewUpdateNeeded;
     }
 
-    public void bind(final JPanel panel) {
+    private void bind(final JPanel panel) {
         panel.addMouseMotionListener(this);
 
         panel.addKeyListener(this);
@@ -75,60 +72,84 @@ public class UserInputTracker
         panel.addMouseWheelListener(this);
     }
 
-    public boolean handleDetectedKeyEvents() {
-        boolean keyEventsHandled = false;
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private boolean handleKeyboardEvents() {
+        final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusTracker().getCurrentFocusOwner();
+        ArrayList<KeyEvent> unprocessedKeyboardEvents = getUnprocessedKeyboardEvents();
 
-        final UserInputHandler currentFocusOwner = viewContext.getKeyboardFocusTracker().getCurrentFocusOwner();
+        return currentFocusOwner == null ? false :
+                forwardKeyboardEventsToFocusOwner(currentFocusOwner, unprocessedKeyboardEvents);
+    }
 
+    private ArrayList<KeyEvent> getUnprocessedKeyboardEvents() {
         synchronized (detectedKeyEvents) {
-            if (currentFocusOwner == null) {
-                detectedKeyEvents.clear();
-                return false;
-            }
-
-            while (!detectedKeyEvents.isEmpty()) {
-                final KeyEvent keyEvent = detectedKeyEvents.remove(0);
-
-                switch (keyEvent.getID()) {
-                    case KeyEvent.KEY_PRESSED:
-                        currentFocusOwner.keyPressed(keyEvent, viewContext);
-                        keyEventsHandled = true;
-                        break;
-
-                    case KeyEvent.KEY_RELEASED:
-                        currentFocusOwner.keyReleased(keyEvent, viewContext);
-                        keyEventsHandled = true;
-                        break;
-                }
-            }
+            ArrayList<KeyEvent> result = new ArrayList<>(detectedKeyEvents);
+            detectedKeyEvents.clear();
+            return result;
         }
+    }
+
+    /**
+     * @return <code>true</code> if view update is needed.
+     */
+    private boolean forwardKeyboardEventsToFocusOwner(
+            UserInputHandler currentFocusOwner, ArrayList<KeyEvent> keyEvents) {
+        boolean viewUpdateNeeded = false;
 
-        return keyEventsHandled;
+        for (KeyEvent keyEvent : keyEvents)
+            viewUpdateNeeded |= processKeyEvent(currentFocusOwner, keyEvent);
+
+        return viewUpdateNeeded;
+    }
+
+    private boolean processKeyEvent(UserInputHandler currentFocusOwner, KeyEvent keyEvent) {
+        switch (keyEvent.getID()) {
+            case KeyEvent.KEY_PRESSED:
+                return currentFocusOwner.keyPressed(keyEvent, viewPanel);
+
+            case KeyEvent.KEY_RELEASED:
+                return currentFocusOwner.keyReleased(keyEvent, viewPanel);
+        }
+        return false;
     }
 
     /**
-     * Returns <code>true</code> if mouse events are detected and view needs to
-     * be repainted.
+     * @return <code>true</code> if view needs to be repainted.
      */
-    public synchronized boolean handleDetectedMouseClicks(final View view) {
-        if (detectedMouseClicks.isEmpty()) {
+    private synchronized boolean handleMouseClicksAndHover(final ViewPanel viewPanel) {
+        MouseClick unprocessedMouseClick = findUnprocessedMouseClick();
+
+        if (unprocessedMouseClick != null) {
+            viewPanel.getRenderingContext().mouseClick = unprocessedMouseClick;
+            return false;
+        } else
+            return handleMouseHovering(viewPanel);
+    }
 
-            if (currentMouseLocation != null)
-                view.getRenderingContext().mouseClick = new MouseClick(currentMouseLocation, 0);
+    private MouseClick findUnprocessedMouseClick() {
+        synchronized (detectedMouseClicks) {
+            if (detectedMouseClicks.isEmpty())
+                return null;
 
-            if (mouseMoved) {
-                mouseMoved = false;
-                return true;
-            } else
-                return false;
+            return detectedMouseClicks.remove(0);
         }
+    }
 
-        view.getRenderingContext().mouseClick = detectedMouseClicks.remove(0);
+    private boolean handleMouseHovering(ViewPanel viewPanel) {
+        if (currentMouseLocation != null)
+            // mouse click with button 0 amounts to mouse hovering event
+            viewPanel.getRenderingContext().mouseClick = new MouseClick(currentMouseLocation, 0);
 
-        return true;
+        if (mouseMoved) {
+            mouseMoved = false;
+            return true;
+        } else
+            return false;
     }
 
-    public boolean isKeyPressed(final int keyCode) {
+    boolean isKeyPressed(final int keyCode) {
         return pressedKeysToPressedTimeMap.containsKey(keyCode);
     }
 
@@ -137,7 +158,6 @@ public class UserInputTracker
         synchronized (detectedKeyEvents) {
             pressedKeysToPressedTimeMap.put(evt.getKeyCode(), System.currentTimeMillis());
             detectedKeyEvents.add(evt);
-            viewContext.getView().repaintDuringNextViewUpdate();
         }
     }
 
@@ -146,7 +166,6 @@ public class UserInputTracker
         synchronized (detectedKeyEvents) {
             pressedKeysToPressedTimeMap.remove(evt.getKeyCode());
             detectedKeyEvents.add(evt);
-            viewContext.getView().repaintDuringNextViewUpdate();
         }
     }
 
@@ -207,15 +226,25 @@ public class UserInputTracker
     }
 
     /**
-     * Interpret mouse movement
+     * @return <code>true</code> if view needs to be repainted.
      */
-    public boolean trackMouse() {
-        final Avatar avatar = viewContext.getAvatar();
-
-        // track mouse dragging
+    private boolean handleMouseVerticalScrolling() {
+        final Avatar avatar = viewPanel.getAvatar();
+        final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
+        avatar.getMovementVector().y += (wheelMovedDirection * actualAcceleration);
+        avatar.enforceSpeedLimit();
+        boolean repaintNeeded = wheelMovedDirection != 0;
+        wheelMovedDirection = 0;
+        return repaintNeeded;
+    }
 
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private boolean handleMouseDragging() {
         // TODO: need to detect whether user moved mouse or touch screen
 
+        final Avatar avatar = viewPanel.getAvatar();
         // for mouse
         avatar.setAngleXZ(avatar.getAngleXZ() - ((float) mouseDraggedDirection.x / 50));
         avatar.setAngleYZ(avatar.getAngleYZ() - ((float) mouseDraggedDirection.y / 50));
@@ -226,21 +255,9 @@ public class UserInputTracker
         // avatar.setAngleYZ(avatar.getAngleYZ() + ((float)
         // mouseDraggedDirection.y / 50));
 
-        // track mouse wheel movements
-        final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
-
-        avatar.getMovementDirection().y += (wheelMovedDirection * actualAcceleration);
-        avatar.enforceSpeedLimit();
-
-        // check if view shall be repainted
-        boolean repaintNeeded;
-        repaintNeeded = (mouseDraggedDirection.x != 0) || (mouseDraggedDirection.y != 0) || (wheelMovedDirection != 0);
-
-        // reset movement counters
-        wheelMovedDirection = 0;
+        boolean viewUpdateNeeded = !mouseDraggedDirection.isZero();
         mouseDraggedDirection.zero();
-
-        return repaintNeeded;
+        return viewUpdateNeeded;
     }
 
 }