Improved input event handling

- Added Component.passInputToChildren()
- Input events can now be processed in parallel or recursively
This commit is contained in:
OLEGSHA 2021-12-21 00:31:35 +03:00
parent f350467942
commit 92f9639c4b
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
2 changed files with 20 additions and 11 deletions

View File

@ -562,6 +562,10 @@ public class Component extends Named {
} }
} }
protected boolean passInputToChildren(InputEvent e) {
return true;
}
InputBus getInputBus() { InputBus getInputBus() {
return inputBus; return inputBus;
} }

View File

@ -27,6 +27,7 @@ import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.input.InputEvent; import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.bus.InputBus; import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
import ru.windcorp.progressia.common.util.LowOverheadCache;
import ru.windcorp.progressia.common.util.StashingStack; import ru.windcorp.progressia.common.util.StashingStack;
public abstract class GUILayer extends AssembledFlatLayer { public abstract class GUILayer extends AssembledFlatLayer {
@ -75,9 +76,11 @@ public abstract class GUILayer extends AssembledFlatLayer {
} }
/** /**
* Stack for {@link #handleInput(InputEvent)}. * Stacks for {@link #handleInput(InputEvent)}.
*/ */
private StashingStack<EventHandlingFrame> path = new StashingStack<>(64, EventHandlingFrame::new); private final LowOverheadCache<StashingStack<EventHandlingFrame>> pathCache = new LowOverheadCache<>(
() -> new StashingStack<>(64, EventHandlingFrame::new)
);
/* /*
* This is essentially a depth-first iteration of the component tree. The * This is essentially a depth-first iteration of the component tree. The
@ -85,10 +88,10 @@ public abstract class GUILayer extends AssembledFlatLayer {
*/ */
@Override @Override
public void handleInput(InputEvent event) { public void handleInput(InputEvent event) {
StashingStack<EventHandlingFrame> path = pathCache.grab();
if (!path.isEmpty()) { if (!path.isEmpty()) {
throw new IllegalStateException( throw new IllegalStateException("path is not empty: " + path);
"path is not empty: " + path + ". Are events being processed concurrently?"
);
} }
path.push().init(root); path.push().init(root);
@ -101,7 +104,7 @@ public abstract class GUILayer extends AssembledFlatLayer {
Component c = it.next(); Component c = it.next();
if (c.isEnabled()) { if (c.isEnabled()) {
if (c.getChildren().isEmpty()) { if (c.getChildren().isEmpty() || !c.passInputToChildren(event)) {
c.getInputBus().dispatch(event); c.getInputBus().dispatch(event);
} else { } else {
path.push().init(c); path.push().init(c);
@ -114,6 +117,8 @@ public abstract class GUILayer extends AssembledFlatLayer {
} }
} }
pathCache.release(path);
} }
private void attemptFocusTransfer(KeyEvent e) { private void attemptFocusTransfer(KeyEvent e) {