import eu.svjatoslav.sixth.e3d.geometry.Box;
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
-import eu.svjatoslav.sixth.e3d.gui.humaninput.UserInputHandler;
-import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.KeyboardHelper;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardInputHandler;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardHelper;
import eu.svjatoslav.sixth.e3d.math.Transform;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
import java.awt.event.KeyEvent;
public class GuiComponent extends AbstractCompositeShape implements
- UserInputHandler, MouseInteractionController {
+ KeyboardInputHandler, MouseInteractionController {
private static final String GROUP_GUI_FOCUS = "gui.focus";
public final ViewPanel viewPanel;
setDimensions(size);
}
- @Override
- public boolean beforeRender(final ViewPanel viewPanel,
- final int millisecondsSinceLastFrame) {
- return false;
- }
-
private WireframeBox createBorder() {
final LineAppearance appearance = new LineAppearance(10,
new eu.svjatoslav.sixth.e3d.renderer.raster.Color(255, 0, 0, 100));
public interface ViewRenderListener {
/**
- * Notifies that it is about time to render next frame and
+ * Notifies that it is about time (to keep constant framerate) to render next frame and
* allows listener to do any related processing that it needs to.
* <p>
* Each {@link ViewRenderListener} will be notified exactly once before every frame is rendered.
* <p>
* {@link ViewRenderListener} can determine if frame repaint is actually
* needed from its perspective. Frame will be rendered only if at least one listener says yes.
+ * This mechanism allows to save computing power and energy by skipping frame rendering when possible.
*
* @return <code>true</code> if underlying view shall be re-rendered. If at least one of the view update listeners
* returns <code>true</code>, view is re-rendered.
/*
- * Sixth 3D engine. Author: Svjatoslav Agejenko.
+ * Sixth 3D engine. Author: Svjatoslav Agejenko.
* This project is released under Creative Commons Zero (CC0) license.
*/
package eu.svjatoslav.sixth.e3d.gui.humaninput;
import java.util.List;
import java.util.Map;
+/**
+ * Human input device input tracker.
+ * <p>
+ * Idea is to capture all keyboard and mouse inputs from underlying operating system in this class
+ * and forward those as needed to subsequent virtual components.
+ */
public class HIDInputTracker implements
MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewRenderListener {
* @return <code>true</code> if view needs to be repainted.
*/
private boolean handleKeyboardEvents() {
- final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusStack().getCurrentFocusOwner();
+ final KeyboardInputHandler currentFocusOwner = viewPanel.getKeyboardFocusStack().getCurrentFocusOwner();
ArrayList<KeyEvent> unprocessedKeyboardEvents = getUnprocessedKeyboardEvents();
return currentFocusOwner != null
* @return <code>true</code> if view update is needed.
*/
private boolean forwardKeyboardEventsToFocusOwner(
- UserInputHandler currentFocusOwner, ArrayList<KeyEvent> keyEvents) {
+ KeyboardInputHandler currentFocusOwner, ArrayList<KeyEvent> keyEvents) {
boolean viewUpdateNeeded = false;
for (KeyEvent keyEvent : keyEvents)
return viewUpdateNeeded;
}
- private boolean processKeyEvent(UserInputHandler currentFocusOwner, KeyEvent keyEvent) {
+ private boolean processKeyEvent(KeyboardInputHandler currentFocusOwner, KeyEvent keyEvent) {
switch (keyEvent.getID()) {
case KeyEvent.KEY_PRESSED:
return currentFocusOwner.keyPressed(keyEvent, viewPanel);
private synchronized boolean handleMouseClicksAndHover(final ViewPanel viewPanel) {
boolean rerenderNeeded = false;
MouseEvent event = findClickLocationToTrace();
- if (event != null){
+ if (event != null) {
// process mouse clicks as a first priority
rerenderNeeded = true;
} else {
* @return <code>true</code> if view needs to be repainted.
*/
private boolean handleMouseDragging() {
- // TODO: need to detect whether user moved mouse or touch screen
+ // TODO: It would be nice here to detect somehow whether user moved mouse or touch screen.
+ // in case of touch screen, we would like to reverse movement along X and Y axis.
final Avatar avatar = viewPanel.getAvatar();
// for mouse
private final ViewPanel viewPanel;
private WorldNavigationUserInputTracker defaultInputHandler = new WorldNavigationUserInputTracker();
- private Stack<UserInputHandler> inputHandlers = new Stack<>();
- private UserInputHandler currentUserInputHandler;
+ private Stack<KeyboardInputHandler> inputHandlers = new Stack<>();
+ private KeyboardInputHandler currentUserInputHandler;
public KeyboardFocusStack(final ViewPanel viewPanel) {
this.viewPanel = viewPanel;
pushFocusOwner(defaultInputHandler);
}
- public UserInputHandler getCurrentFocusOwner() {
+ public KeyboardInputHandler getCurrentFocusOwner() {
return currentUserInputHandler;
}
currentUserInputHandler.focusReceived(viewPanel);
}
- public boolean pushFocusOwner(final UserInputHandler newInputHandler) {
+ public boolean pushFocusOwner(final KeyboardInputHandler newInputHandler) {
boolean updateNeeded = false;
if (currentUserInputHandler == newInputHandler)
--- /dev/null
+/*
+ * Sixth 3D engine. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+package eu.svjatoslav.sixth.e3d.gui.humaninput;
+
+import java.awt.event.InputEvent;
+import java.util.HashSet;
+import java.util.Set;
+
+public class KeyboardHelper {
+
+ public static final int TAB = 9;
+ public static final int DOWN = 40;
+ public static final int UP = 38;
+ public static final int RIGHT = 39;
+ public static final int LEFT = 37;
+ public static final int PGDOWN = 34;
+ public static final int PGUP = 33;
+ public static final int HOME = 36;
+ public static final int END = 35;
+ public static final int DEL = 127;
+ public static final int ENTER = 10;
+ public static final int BACKSPACE = 8;
+ public static final int ESC = 27;
+ public static final int SHIFT = 16;
+
+ private static final Set<Integer> nonText;
+
+ static {
+ nonText = new HashSet<>();
+ nonText.add(DOWN);
+ nonText.add(UP);
+ nonText.add(LEFT);
+ nonText.add(RIGHT);
+
+ nonText.add(SHIFT);
+ nonText.add(ESC);
+ }
+
+ public static boolean isAltPressed(final int modifiersEx) {
+ return (modifiersEx | InputEvent.ALT_DOWN_MASK) == modifiersEx;
+ }
+
+ public static boolean isCtrlPressed(final int modifiersEx) {
+ return (modifiersEx | InputEvent.CTRL_DOWN_MASK) == modifiersEx;
+ }
+
+ public static boolean isShiftPressed(final int modifiersEx) {
+ return (modifiersEx | InputEvent.SHIFT_DOWN_MASK) == modifiersEx;
+ }
+
+ public static boolean isText(final int keyCode) {
+ return !nonText.contains(keyCode);
+ }
+
+}
--- /dev/null
+/*
+ * Sixth 3D engine. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+package eu.svjatoslav.sixth.e3d.gui.humaninput;
+
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+
+import java.awt.event.KeyEvent;
+
+/**
+ * This is the process:
+ *
+ * 1. Component receives focus, perhaps because user clicked on it with the mouse.
+ * 2. Now component will receive user key press and release events from the keyboard.
+ * 3. Component loses focus. Perhaps user chose another component to interact with.
+ */
+public interface KeyboardInputHandler {
+
+ /**
+ * @return <code>true</code> if view needs to be re-rendered.
+ */
+ boolean focusLost(ViewPanel viewPanel);
+
+ /**
+ * @return <code>true</code> if view needs to be re-rendered.
+ */
+ boolean focusReceived(ViewPanel viewPanel);
+
+ /**
+ * @return <code>true</code> if view needs to be re-rendered.
+ */
+ boolean keyPressed(KeyEvent event, ViewPanel viewPanel);
+
+ /**
+ * @return <code>true</code> if view needs to be re-rendered.
+ */
+ boolean keyReleased(KeyEvent event, ViewPanel viewPanel);
+
+}
+++ /dev/null
-/*
- * Sixth 3D engine. Author: Svjatoslav Agejenko.
- * This project is released under Creative Commons Zero (CC0) license.
- */
-package eu.svjatoslav.sixth.e3d.gui.humaninput;
-
-import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
-import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener;
-
-import java.awt.event.KeyEvent;
-
-public interface UserInputHandler extends ViewRenderListener {
-
- /**
- * @return <code>true</code> if view update is needed.
- */
- boolean focusLost(ViewPanel viewPanel);
-
- /**
- * @return <code>true</code> if view update is needed.
- */
- boolean focusReceived(ViewPanel viewPanel);
-
- /**
- * @return <code>true</code> if view update is needed.
- */
- boolean keyPressed(KeyEvent event, ViewPanel viewPanel);
-
- /**
- * @return <code>true</code> if view update is needed.
- */
- boolean keyReleased(KeyEvent event, ViewPanel viewPanel);
-
-}
import eu.svjatoslav.sixth.e3d.gui.Avatar;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
-import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.KeyboardHelper;
+import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener;
import java.awt.event.KeyEvent;
-public class WorldNavigationUserInputTracker implements UserInputHandler {
+public class WorldNavigationUserInputTracker implements KeyboardInputHandler, ViewRenderListener {
@Override
public boolean beforeRender(final ViewPanel viewPanel,
+++ /dev/null
-/*
- * Sixth 3D engine. Author: Svjatoslav Agejenko.
- * This project is released under Creative Commons Zero (CC0) license.
- */
-package eu.svjatoslav.sixth.e3d.gui.textEditorComponent;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class KeyboardHelper {
-
- public static final int TAB = 9;
- public static final int DOWN = 40;
- public static final int UP = 38;
- public static final int RIGHT = 39;
- public static final int LEFT = 37;
- public static final int PGDOWN = 34;
- public static final int PGUP = 33;
- public static final int HOME = 36;
- public static final int END = 35;
- public static final int DEL = 127;
- public static final int ENTER = 10;
- public static final int BACKSPACE = 8;
- public static final int ESC = 27;
- public static final int SHIFT = 16;
-
- private static final Set<Integer> nonText;
-
- static {
- nonText = new HashSet<>();
- nonText.add(DOWN);
- nonText.add(UP);
- nonText.add(LEFT);
- nonText.add(RIGHT);
-
- nonText.add(SHIFT);
- nonText.add(ESC);
- }
-
- public static boolean isAlt(final int modifiers) {
- return (modifiers | 8) == modifiers;
- }
-
- public static boolean isCtrl(final int modifiers) {
- return (modifiers | 2) == modifiers;
- }
-
- public static boolean isShift(final int modifiers) {
- return (modifiers | 1) == modifiers;
- }
-
- public static boolean isText(final int keyCode) {
- return !nonText.contains(keyCode);
- }
-
-}
import eu.svjatoslav.sixth.e3d.gui.GuiComponent;
import eu.svjatoslav.sixth.e3d.gui.TextPointer;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardHelper;
import eu.svjatoslav.sixth.e3d.math.Transform;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas;
public class TextEditComponent extends GuiComponent implements ClipboardOwner {
private static final long serialVersionUID = -7118833957783600630L;
- // lines that need to be repainted
+
+ /**
+ * Text rows that need to be repainted.
+ */
private final Set<Integer> dirtyRows = new HashSet<>();
+
private final TextCanvas textCanvas;
public int scrolledCharacters = 0, scrolledLines = 0;
public boolean selecting = false;
public TextPointer selectionStart = new TextPointer(0, 0);
public TextPointer selectionEnd = new TextPointer(0, 0);
- public TextPointer cursorLocation;
+ public TextPointer cursorLocation = new TextPointer(0, 0);
Page page = new Page();
ColorConfig colorConfig = new ColorConfig();
boolean repaintPage = false;
public TextEditComponent(final Transform transform,
- final ViewPanel viewPanel, final Point2D size) {
- super(transform, viewPanel, size.to3D());
-
- cursorLocation = new TextPointer(0, 0);
+ final ViewPanel viewPanel, final Point2D sizeInWorldCoordinates) {
+ super(transform, viewPanel, sizeInWorldCoordinates.to3D());
// initialize visual panel
- final int columns = (int) (size.x / TextCanvas.FONT_CHAR_WIDTH);
- final int rows = (int) (size.y / TextCanvas.FONT_CHAR_HEIGHT);
+ final int columns = (int) (sizeInWorldCoordinates.x / TextCanvas.FONT_CHAR_WIDTH);
+ final int rows = (int) (sizeInWorldCoordinates.y / TextCanvas.FONT_CHAR_HEIGHT);
textCanvas = new TextCanvas(new Transform(), new TextPointer(rows,
columns), Color.WHITE, colorConfig.normalBack);
}
private void processKeyEvent(final KeyEvent event) {
- final int modifiers = event.getModifiers();
-
+ final int modifiers = event.getModifiersEx();
final int keyCode = event.getKeyCode();
final char keyChar = event.getKeyChar();
// System.out.println("Keycode:" + keyCode s+ ", keychar:" + keyChar);
- if (KeyboardHelper.isAlt(modifiers))
+ if (KeyboardHelper.isAltPressed(modifiers))
return;
- if (KeyboardHelper.isCtrl(modifiers)) {
+ if (KeyboardHelper.isCtrlPressed(modifiers)) {
processCtrlCombinations(keyCode);
return;
}
return;
}
- // System.out.println("Co:" + String.valueOf(code) + " Ch:" +
- // String.valueOf(keyChar));
-
- if (KeyboardHelper.isShift(modifiers)) {
+ if (KeyboardHelper.isShiftPressed(modifiers)) {
if (!selecting)
attemptSelectionStart:{
| (keyChar == 8) | (keyChar == 9))
break attemptSelectionStart;
- // System.out.println("Selection started:" + keyChar + " "
- // + keyCode);
-
selectionStart = new TextPointer(cursorLocation);
selectionEnd = selectionStart;
selecting = true;
}
private void processTab(final int modifiers) {
- if (KeyboardHelper.isShift(modifiers)) {
+ if (KeyboardHelper.isShiftPressed(modifiers)) {
if (selectionStart.compareTo(selectionEnd) != 0) {
// dedent multiple lines
ensureSelectionOrder();