Add support for key event handling in GUI

This commit is contained in:
2021-03-13 11:22:48 +01:00
parent 5cb9e9fb75
commit 68e0a793aa
17 changed files with 80 additions and 30 deletions

View File

@@ -5,7 +5,6 @@ import com.bartlomiejpluta.base.api.game.entity.Entity;
import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.image.Image; import com.bartlomiejpluta.base.api.game.image.Image;
import com.bartlomiejpluta.base.api.game.input.Input; import com.bartlomiejpluta.base.api.game.input.Input;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.runner.GameRunner;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import com.bartlomiejpluta.base.api.internal.gc.Disposable; import com.bartlomiejpluta.base.api.internal.gc.Disposable;
@@ -46,6 +45,4 @@ public interface Context extends Updatable, Renderable, Disposable {
void init(Screen screen, Input input, Camera camera); void init(Screen screen, Input input, Camera camera);
void input(Input input); void input(Input input);
void handleKeyEvent(KeyEvent event);
} }

View File

@@ -1,5 +1,7 @@
package com.bartlomiejpluta.base.api.game.gui.base; package com.bartlomiejpluta.base.api.game.gui.base;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
public abstract class BaseWidget implements Widget { public abstract class BaseWidget implements Widget {
protected Widget parent; protected Widget parent;
@@ -271,4 +273,9 @@ public abstract class BaseWidget implements Widget {
public float getPaddingLeft() { public float getPaddingLeft() {
return paddingLeft; return paddingLeft;
} }
@Override
public void handleKeyEvent(KeyEvent event) {
// Designed to be overridden if needed so
}
} }

View File

@@ -1,9 +1,10 @@
package com.bartlomiejpluta.base.api.game.gui.base; package com.bartlomiejpluta.base.api.game.gui.base;
import com.bartlomiejpluta.base.api.game.input.KeyEventHandler;
import com.bartlomiejpluta.base.api.internal.gc.Disposable; import com.bartlomiejpluta.base.api.internal.gc.Disposable;
import com.bartlomiejpluta.base.api.internal.render.Renderable; import com.bartlomiejpluta.base.api.internal.render.Renderable;
public interface GUI extends Renderable, Disposable { public interface GUI extends Renderable, Disposable, KeyEventHandler {
int ALIGN_LEFT = 1 << 0; int ALIGN_LEFT = 1 << 0;
int ALIGN_CENTER = 1 << 1; int ALIGN_CENTER = 1 << 1;
int ALIGN_RIGHT = 1 << 2; int ALIGN_RIGHT = 1 << 2;

View File

@@ -1,8 +1,9 @@
package com.bartlomiejpluta.base.api.game.gui.base; package com.bartlomiejpluta.base.api.game.gui.base;
import com.bartlomiejpluta.base.api.game.input.KeyEventHandler;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
public interface Widget { public interface Widget extends KeyEventHandler {
Widget getParent(); Widget getParent();
void setParent(Widget parent); void setParent(Widget parent);

View File

@@ -1,5 +1,7 @@
package com.bartlomiejpluta.base.api.game.gui.component; package com.bartlomiejpluta.base.api.game.gui.component;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -63,4 +65,15 @@ public abstract class BaseContainer extends BaseComponent implements Container {
return childrenHeight; return childrenHeight;
} }
@Override
public void handleKeyEvent(KeyEvent event) {
for (var child : children) {
if (!event.isConsumed()) {
return;
}
child.handleKeyEvent(event);
}
}
} }

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.api.game.gui.window;
import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget; import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget;
import com.bartlomiejpluta.base.api.game.gui.component.Component; import com.bartlomiejpluta.base.api.game.gui.component.Component;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
public abstract class BaseWindow extends BaseWidget implements Window { public abstract class BaseWindow extends BaseWidget implements Window {
protected Component content; protected Component content;
@@ -36,4 +37,9 @@ public abstract class BaseWindow extends BaseWidget implements Window {
public void onClose(WindowManager manager) { public void onClose(WindowManager manager) {
// do nothing // do nothing
} }
@Override
public void handleKeyEvent(KeyEvent event) {
content.handleKeyEvent(event);
}
} }

View File

@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.api.game.gui.window;
import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget; import com.bartlomiejpluta.base.api.game.gui.base.BaseWidget;
import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.gui.base.SizeMode; import com.bartlomiejpluta.base.api.game.gui.base.SizeMode;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import java.util.Deque; import java.util.Deque;
@@ -68,6 +69,11 @@ public class DefaultWindowManager extends BaseWidget implements WindowManager {
window.onClose(this); window.onClose(this);
} }
@Override
public int size() {
return windows.size();
}
@Override @Override
public void draw(Screen screen, GUI gui) { public void draw(Screen screen, GUI gui) {
switch (displayMode) { switch (displayMode) {
@@ -86,6 +92,14 @@ public class DefaultWindowManager extends BaseWidget implements WindowManager {
} }
} }
@Override
public void handleKeyEvent(KeyEvent event) {
var topWindow = windows.peekFirst();
if (topWindow != null) {
topWindow.handleKeyEvent(event);
}
}
private void drawWindow(Screen screen, Window window, GUI gui) { private void drawWindow(Screen screen, Window window, GUI gui) {
switch (window.getWindowPosition()) { switch (window.getWindowPosition()) {
case TOP -> window.setPosition( case TOP -> window.setPosition(

View File

@@ -8,4 +8,6 @@ public interface WindowManager extends Widget {
void open(Window window); void open(Window window);
void close(); void close();
int size();
} }

View File

@@ -1,11 +1,9 @@
package com.bartlomiejpluta.base.api.game.input; package com.bartlomiejpluta.base.api.game.input;
import java.util.function.Consumer;
public interface Input { public interface Input {
boolean isKeyPressed(Key key); boolean isKeyPressed(Key key);
void addKeyEventHandler(Consumer<KeyEvent> handler); void addKeyEventHandler(KeyEventHandler handler);
void removeKeyEventHandler(Consumer<KeyEvent> handler); void removeKeyEventHandler(KeyEventHandler handler);
} }

View File

@@ -0,0 +1,5 @@
package com.bartlomiejpluta.base.api.game.input;
public interface KeyEventHandler {
void handleKeyEvent(KeyEvent event);
}

View File

@@ -4,6 +4,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.context.Context;
import com.bartlomiejpluta.base.api.game.input.Input;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.runner.GameRunner;
@@ -12,6 +13,9 @@ public class ${className} implements GameRunner {
@Override @Override
public void init(Context context) { public void init(Context context) {
// Resume engine, because it is initially paused
context.resume();
log.info("The game runner is not implemented yet..."); log.info("The game runner is not implemented yet...");
throw new RuntimeException("Not implemented yet"); throw new RuntimeException("Not implemented yet");
} }

View File

@@ -1,6 +1,7 @@
package ${package}; package ${package};
import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.context.Context;
import com.bartlomiejpluta.base.api.game.input.Input;
import com.bartlomiejpluta.base.api.game.map.model.GameMap; import com.bartlomiejpluta.base.api.game.map.model.GameMap;
import com.bartlomiejpluta.base.api.game.map.handler.MapHandler; import com.bartlomiejpluta.base.api.game.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
@@ -18,7 +19,7 @@ public class ${className} implements MapHandler {
} }
@Override @Override
public void input(Screen screen) { public void input(Input input) {
} }

View File

@@ -6,7 +6,6 @@ import com.bartlomiejpluta.base.api.game.entity.Entity;
import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.image.Image; import com.bartlomiejpluta.base.api.game.image.Image;
import com.bartlomiejpluta.base.api.game.input.Input; import com.bartlomiejpluta.base.api.game.input.Input;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import com.bartlomiejpluta.base.api.game.map.handler.MapHandler; import com.bartlomiejpluta.base.api.game.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.runner.GameRunner;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
@@ -137,11 +136,6 @@ public class DefaultContext implements Context {
return engine.togglePaused(); return engine.togglePaused();
} }
@Override
public void handleKeyEvent(KeyEvent event) {
// TODO
}
@Override @Override
public void input(Input input) { public void input(Input input) {
gameRunner.input(input); gameRunner.input(input);

View File

@@ -5,6 +5,7 @@ import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.gui.base.LineCap; import com.bartlomiejpluta.base.api.game.gui.base.LineCap;
import com.bartlomiejpluta.base.api.game.gui.base.Widget; import com.bartlomiejpluta.base.api.game.gui.base.Widget;
import com.bartlomiejpluta.base.api.game.gui.base.WindingDirection; import com.bartlomiejpluta.base.api.game.gui.base.WindingDirection;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import com.bartlomiejpluta.base.api.internal.render.ShaderManager; import com.bartlomiejpluta.base.api.internal.render.ShaderManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
@@ -245,6 +246,11 @@ public class NanoVGGUI implements GUI {
nvgScissor(context, x, y, width, height); nvgScissor(context, x, y, width, height);
} }
@Override
public void handleKeyEvent(KeyEvent event) {
screenWidget.handleKeyEvent(event);
}
@Override @Override
public void dispose() { public void dispose() {
fillColor.free(); fillColor.free();

View File

@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.engine.gui.widget;
import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.gui.base.SizeMode; import com.bartlomiejpluta.base.api.game.gui.base.SizeMode;
import com.bartlomiejpluta.base.api.game.gui.base.Widget; import com.bartlomiejpluta.base.api.game.gui.base.Widget;
import com.bartlomiejpluta.base.api.game.input.KeyEvent;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -231,6 +232,11 @@ public class ScreenWidget implements Widget {
return 0; return 0;
} }
@Override
public void handleKeyEvent(KeyEvent event) {
root.handleKeyEvent(event);
}
@Override @Override
public void draw(Screen screen, GUI gui) { public void draw(Screen screen, GUI gui) {
if (root != null) { if (root != null) {

View File

@@ -33,13 +33,10 @@ public class DefaultGameLogic implements GameLogic {
camera = new DefaultCamera(); camera = new DefaultCamera();
log.info("Initializing input model"); log.info("Initializing input model");
var input = new GLFWInput(screen); input = new GLFWInput(screen).init();
input.init(context);
log.info("Initializing game context"); log.info("Initializing game context");
context.init(screen, input, camera); context.init(screen, input, camera);
this.input = input;
} }
@Override @Override

View File

@@ -1,9 +1,8 @@
package com.bartlomiejpluta.base.engine.ui.model; package com.bartlomiejpluta.base.engine.ui.model;
import com.bartlomiejpluta.base.api.game.context.Context;
import com.bartlomiejpluta.base.api.game.input.Input; import com.bartlomiejpluta.base.api.game.input.Input;
import com.bartlomiejpluta.base.api.game.input.Key; import com.bartlomiejpluta.base.api.game.input.Key;
import com.bartlomiejpluta.base.api.game.input.KeyEvent; import com.bartlomiejpluta.base.api.game.input.KeyEventHandler;
import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.game.screen.Screen;
import com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent; import com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent;
import lombok.NonNull; import lombok.NonNull;
@@ -11,7 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import java.util.Deque; import java.util.Deque;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.function.Consumer;
import static com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent.glfwCode; import static com.bartlomiejpluta.base.engine.ui.event.GLFWKeyEvent.glfwCode;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
@@ -19,27 +17,27 @@ import static org.lwjgl.glfw.GLFW.*;
@Slf4j @Slf4j
public class GLFWInput implements Input { public class GLFWInput implements Input {
private final long windowHandle; private final long windowHandle;
private final Deque<Consumer<KeyEvent>> keyEventHandlers = new LinkedList<>(); private final Deque<KeyEventHandler> keyEventHandlers = new LinkedList<>();
public GLFWInput(@NonNull Screen screen) { public GLFWInput(@NonNull Screen screen) {
this.windowHandle = screen.getID(); this.windowHandle = screen.getID();
} }
public void init(Context context) { public GLFWInput init() {
log.info("Registering key callback"); log.info("Registering key callback");
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> { glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
var event = GLFWKeyEvent.of(key, action); var event = GLFWKeyEvent.of(key, action);
context.handleKeyEvent(event);
for (var handler : keyEventHandlers) { for (var handler : keyEventHandlers) {
if (event.isConsumed()) { if (event.isConsumed()) {
return; return;
} }
handler.accept(event); handler.handleKeyEvent(event);
} }
}); });
return this;
} }
@Override @Override
@@ -48,12 +46,12 @@ public class GLFWInput implements Input {
} }
@Override @Override
public void addKeyEventHandler(Consumer<KeyEvent> handler) { public void addKeyEventHandler(KeyEventHandler handler) {
keyEventHandlers.addLast(handler); keyEventHandlers.addLast(handler);
} }
@Override @Override
public void removeKeyEventHandler(Consumer<KeyEvent> handler) { public void removeKeyEventHandler(KeyEventHandler handler) {
keyEventHandlers.remove(handler); keyEventHandlers.remove(handler);
} }
} }