Skip to content

Commit

Permalink
Add focus management to UI components
Browse files Browse the repository at this point in the history
This commit introduces focus handling capabilities to UI components, providing methods for components to gain or lose focus. The changes include updating the handling of keyboard events to streamline focus management and integrating focus functions into the existing `BasePLScreen` and `VanillaUIComponent` classes. These enhancements improve user interaction by ensuring that UI components correctly respond to focus changes.
  • Loading branch information
ThePandaOliver committed Dec 8, 2024
1 parent 422a969 commit 61c055c
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import me.pandamods.pandalib.client.screen.layouts.StackContainer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.Component;

public class TestScreen extends BasePLScreen<StackContainer> {
Expand All @@ -31,9 +32,12 @@ protected void build(StackContainer rootComponent) {
button -> System.out.println("Test click"))
.width(200)
.build());

vanillaTestButton.mount(rootComponent);

EditBox editBox = new EditBox(Minecraft.getInstance().font, 0, 0, 200, 20, Component.literal("Test TextField"));
VanillaUIComponent vanillaTestTextField = VanillaUIComponent.of(editBox);
vanillaTestTextField.mount(rootComponent);

TextUIComponent textUIComponent = new TextUIComponent(Minecraft.getInstance().font, Component.literal("Test Text"));
textUIComponent.mount(rootComponent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,19 @@ public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, doubl

@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
FocusHandler focusHandler = this.rootComponent.getFocusHandler();
if (focusHandler != null && focusHandler.isFocusing() && focusHandler.getFocusedComponent().keyPressed(keyCode, scanCode, modifiers))
return true;
if (this.rootComponent.keyPressed(keyCode, scanCode, modifiers)) return true;
return super.keyPressed(keyCode, scanCode, modifiers);
}

@Override
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
FocusHandler focusHandler = this.rootComponent.getFocusHandler();
if (focusHandler != null && focusHandler.isFocusing() && focusHandler.getFocusedComponent().keyReleased(keyCode, scanCode, modifiers))
return true;
if (this.rootComponent.keyReleased(keyCode, scanCode, modifiers)) return true;
return super.keyReleased(keyCode, scanCode, modifiers);
}

@Override
public boolean charTyped(char codePoint, int modifiers) {
FocusHandler focusHandler = this.rootComponent.getFocusHandler();
if (focusHandler != null && focusHandler.isFocusing() && focusHandler.getFocusedComponent().charTyped(codePoint, modifiers))
return true;
if (this.rootComponent.charTyped(codePoint, modifiers)) return true;
return super.charTyped(codePoint, modifiers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
import org.jetbrains.annotations.Nullable;

public abstract class BaseParentUIComponent extends BaseUIComponent implements ParentUIComponent {
private FocusHandler focusHandler = new FocusHandler(this);
protected FocusHandler focusHandler = new FocusHandler(this);

@Override
public void render(RenderContext context, int mouseX, int mouseY, float partialTicks) {
Runnable renderChildren = () -> renderChildren(context, mouseX, mouseY, partialTicks);
if (this.isOverflowAllowed())
if (this.isOverflowAllowed()) {
renderChildren.run();
else
}else {
context.scissor(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), renderChildren);
}
}

protected void renderChildren(RenderContext context, int mouseX, int mouseY, float partialTicks) {
Expand All @@ -53,12 +54,4 @@ public void updateChildState(UIComponent uiComponent) {

protected abstract void addChild(UIComponent UIComponent);
protected abstract void removeChild(UIComponent UIComponent);

@Override
public @Nullable FocusHandler getFocusHandler() {
FocusHandler focusHandler = super.getFocusHandler();
if (focusHandler == null)
focusHandler = this.focusHandler;
return focusHandler;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import me.pandamods.pandalib.client.screen.core.ParentUIComponent;
import me.pandamods.pandalib.client.screen.core.UIComponent;
import me.pandamods.pandalib.client.screen.utils.FocusHandler;
import org.jetbrains.annotations.Nullable;

public abstract class BaseUIComponent implements UIComponent {
Expand Down Expand Up @@ -43,11 +42,6 @@ public void dismount() {
mount(null);
}

@Override
public @Nullable FocusHandler getFocusHandler() {
return this.hasParent() ? this.getParent().getFocusHandler() : null;
}

@Override
public void setX(int x) {
this.x = x;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,14 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) {
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
return this.widget.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
}

@Override
public void onFocusGained() {
this.widget.setFocused(true);
}

@Override
public void onFocusLost() {
this.widget.setFocused(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

package me.pandamods.pandalib.client.screen.core;

import me.pandamods.pandalib.client.screen.utils.FocusHandler;

import java.util.List;

public interface ParentUIComponent extends UIComponent {
Expand All @@ -36,21 +38,16 @@ default UIComponent getChildAt(int x, int y) {
return isInBoundingBox(x, y) ? this : null;
}

@Override
default boolean keyPressed(int keyCode, int scanCode, int modifiers) {
return UIComponent.super.keyPressed(keyCode, scanCode, modifiers);
}

@Override
default boolean keyReleased(int keyCode, int scanCode, int modifiers) {
return UIComponent.super.keyReleased(keyCode, scanCode, modifiers);
}

@Override
default boolean mousePressed(double mouseX, double mouseY, int button) {
for (UIComponent child : getChildren()) {
if (!child.isInBoundingBox(getX() + mouseX, getY() + mouseY)) continue;
if (child.mousePressed(mouseX, mouseY, button)) return true;
if (child.mousePressed(mouseX, mouseY, button)) {
FocusHandler focusHandler = getFocusHandler();
if (focusHandler != null)
focusHandler.focus(child);
return true;
}
}

return UIComponent.super.mousePressed(mouseX, mouseY, button);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

package me.pandamods.pandalib.client.screen.core;

import me.pandamods.pandalib.client.screen.BasePLScreen;
import me.pandamods.pandalib.client.screen.utils.FocusHandler;
import me.pandamods.pandalib.client.screen.utils.RenderContext;
import org.jetbrains.annotations.Nullable;
import net.minecraft.client.Minecraft;

public interface UIComponent {
void render(RenderContext context, int mouseX, int mouseY, float partialTicks);
Expand All @@ -28,13 +29,19 @@ default boolean hasParent() {
void mount(ParentUIComponent parent);
void dismount();

default boolean isMounted() {
return this.hasParent();
}

default ParentUIComponent root() {
ParentUIComponent root = this.getParent();
while (root.hasParent()) root = root.getParent();
return root;
}

@Nullable FocusHandler getFocusHandler();
default FocusHandler getFocusHandler() {
return this.hasParent() ? this.getParent().getFocusHandler() : null;
}

void setX(int x);
void setY(int y);
Expand All @@ -56,6 +63,7 @@ default void position(int x, int y) {
setX(x);
setY(y);
}

default void size(int width, int height) {
setWidth(width);
setHeight(height);
Expand Down Expand Up @@ -87,4 +95,7 @@ default boolean mouseReleased(double mouseX, double mouseY, int button) {
default boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
return false;
}

default void onFocusGained() {}
default void onFocusLost() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,41 @@

package me.pandamods.pandalib.client.screen.utils;

import me.pandamods.pandalib.client.screen.BaseParentUIComponent;
import me.pandamods.pandalib.client.screen.core.ParentUIComponent;
import me.pandamods.pandalib.client.screen.core.UIComponent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

public class FocusHandler {
protected final ParentUIComponent root;
private final ParentUIComponent root;

protected UIComponent focusedComponent;
@Nullable
protected UIComponent focused;

public FocusHandler(ParentUIComponent root) {
this.root = root;
}

public void setFocused(UIComponent component) {
this.focusedComponent = component;
public void focus(UIComponent focused) {
if (this.focused != null) this.focused.onFocusLost();
this.focused = focused;
if (this.focused != null) this.focused.onFocusGained();
}

public void clearFocus() {
focus(null);
}

@Nullable
public UIComponent getFocusedComponent() {
return focusedComponent;
public UIComponent getFocused() {
return focused;
}

public boolean isFocused(UIComponent component) {
return focused == component;
}

public boolean isFocusing() {
return getFocusedComponent() != null;
public ParentUIComponent getRoot() {
return root;
}
}

0 comments on commit 61c055c

Please sign in to comment.