mirror of
https://github.com/TeamMidnightDust/MidnightControls.git
synced 2025-12-13 15:25:08 +01:00
Add obisidianUI text field interop
This commit is contained in:
@@ -7,7 +7,6 @@ import net.minecraft.client.gui.ParentElement;
|
|||||||
import net.minecraft.client.gui.screen.ChatScreen;
|
import net.minecraft.client.gui.screen.ChatScreen;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -23,25 +22,25 @@ public class DefaultScreenClickHandler extends AbstractScreenClickHandler<Screen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Screen screen, double mouseX, double mouseY) {
|
public void handle(Screen screen, double mouseX, double mouseY) {
|
||||||
var textField = findClickedTextField(screen, mouseX, mouseY);
|
var textField = findClickedTextField(screen.children(), mouseX, mouseY);
|
||||||
if (textField == null) {
|
if (textField == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parentScreen = screen;
|
this.parentScreen = screen;
|
||||||
this.textFieldElementPath = calculatePathToElement(screen, textField);
|
this.textFieldElementPath = calculatePathToElement(screen, textField.asElement());
|
||||||
|
|
||||||
var virtualKeyboardScreen = new VirtualKeyboardScreen(textField.getText(), this::handleKeyboardClose, false);
|
var virtualKeyboardScreen = new VirtualKeyboardScreen(textField.getText(), this::handleKeyboardClose, false);
|
||||||
client.setScreen(virtualKeyboardScreen);
|
client.setScreen(virtualKeyboardScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleKeyboardClose(String newText) {
|
private void handleKeyboardClose(String newText) {
|
||||||
if(this.parentScreen == null || this.textFieldElementPath == null) {
|
if (this.parentScreen == null || this.textFieldElementPath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.setScreen(this.parentScreen);
|
client.setScreen(this.parentScreen);
|
||||||
TextFieldWidget textField = findTextFieldByPath(this.parentScreen, this.textFieldElementPath);
|
TextFieldWrapper textField = findTextFieldByPath(this.parentScreen, this.textFieldElementPath);
|
||||||
if (textField == null) {
|
if (textField == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -57,20 +56,29 @@ public class DefaultScreenClickHandler extends AbstractScreenClickHandler<Screen
|
|||||||
// send the chat message
|
// send the chat message
|
||||||
chatScreen.keyPressed(GLFW.GLFW_KEY_ENTER, 0, 0);
|
chatScreen.keyPressed(GLFW.GLFW_KEY_ENTER, 0, 0);
|
||||||
}
|
}
|
||||||
default -> {}
|
default -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextFieldWidget findClickedTextField(Screen screen, double mouseX, double mouseY) {
|
|
||||||
for (Element element : screen.children()) {
|
private TextFieldWrapper findClickedTextField(List<? extends Element> elements, double mouseX, double mouseY) {
|
||||||
if (element instanceof TextFieldWidget textField) {
|
for (Element element : elements) {
|
||||||
|
if (TextFieldWrapper.isValidTextField(element)) {
|
||||||
|
TextFieldWrapper textField = new TextFieldWrapper(element);
|
||||||
if (textField.isMouseOver(mouseX, mouseY) && textField.isFocused()) {
|
if (textField.isMouseOver(mouseX, mouseY) && textField.isFocused()) {
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element instanceof ParentElement parentElement) {
|
||||||
|
TextFieldWrapper found = findClickedTextField(parentElement.children(), mouseX, mouseY);
|
||||||
|
if (found != null) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not hovering over a text field
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,58 +86,57 @@ public class DefaultScreenClickHandler extends AbstractScreenClickHandler<Screen
|
|||||||
* Calculates the path between a parent and a target in the UI hierarchy
|
* Calculates the path between a parent and a target in the UI hierarchy
|
||||||
*/
|
*/
|
||||||
protected List<Integer> calculatePathToElement(Element parent, Element target) {
|
protected List<Integer> calculatePathToElement(Element parent, Element target) {
|
||||||
if (parent instanceof ParentElement parentElement) {
|
if (!(parent instanceof ParentElement parentElement)) {
|
||||||
List<? extends Element> children = parentElement.children();
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// check direct children first
|
List<? extends Element> children = parentElement.children();
|
||||||
for (int i = 0; i < children.size(); i++) {
|
|
||||||
if (children.get(i) == target) {
|
for (int i = 0; i < children.size(); i++) {
|
||||||
// found it, return the path to this element
|
Element child = children.get(i);
|
||||||
return Collections.singletonList(i);
|
|
||||||
}
|
if (child == target) {
|
||||||
|
return Collections.singletonList(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check each child's children
|
if (child instanceof ParentElement) {
|
||||||
for (int i = 0; i < children.size(); i++) {
|
List<Integer> subPath = calculatePathToElement(child, target);
|
||||||
if (children.get(i) instanceof ParentElement childParent) {
|
if (subPath != null) {
|
||||||
List<Integer> subPath = calculatePathToElement(childParent, target);
|
List<Integer> fullPath = new ArrayList<>(subPath.size() + 1);
|
||||||
if (subPath != null) {
|
fullPath.add(i);
|
||||||
// found in this subtree, prepend current index
|
fullPath.addAll(subPath);
|
||||||
List<Integer> fullPath = new ArrayList<>();
|
return fullPath;
|
||||||
fullPath.add(i);
|
|
||||||
fullPath.addAll(subPath);
|
|
||||||
return fullPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TextFieldWidget findTextFieldByPath(Element parent, List<Integer> path) {
|
protected TextFieldWrapper findTextFieldByPath(Element parent, List<Integer> path) {
|
||||||
if (path == null || path.isEmpty()) {
|
if (path == null || path.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent instanceof ParentElement parentElement) {
|
if (!(parent instanceof ParentElement parentElement)) {
|
||||||
List<? extends Element> children = parentElement.children();
|
return null;
|
||||||
int index = path.getFirst();
|
}
|
||||||
|
|
||||||
if (index >= 0 && index < children.size()) {
|
List<? extends Element> children = parentElement.children();
|
||||||
Element child = children.get(index);
|
int index = path.get(0);
|
||||||
|
|
||||||
if (path.size() == 1) {
|
if (index < 0 || index >= children.size()) {
|
||||||
// This should be our target
|
return null;
|
||||||
return (child instanceof TextFieldWidget) ? (TextFieldWidget) child : null;
|
}
|
||||||
} else {
|
|
||||||
// Continue traversing
|
Element child = children.get(index);
|
||||||
if (child instanceof ParentElement) {
|
|
||||||
return findTextFieldByPath(child, path.subList(1, path.size()));
|
if (path.size() == 1) {
|
||||||
}
|
return TextFieldWrapper.isValidTextField(child) ? new TextFieldWrapper(child) : null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (child instanceof ParentElement) {
|
||||||
|
return findTextFieldByPath(child, path.subList(1, path.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package eu.midnightdust.midnightcontrols.client.virtualkeyboard.clickhandler;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.Element;
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
|
import org.thinkingstudio.obsidianui.widget.text.SpruceTextFieldWidget;
|
||||||
|
|
||||||
|
public record TextFieldWrapper(Object textField) {
|
||||||
|
|
||||||
|
public TextFieldWrapper {
|
||||||
|
if (!isValidTextField(textField)) {
|
||||||
|
throw new IllegalArgumentException("Type " + textField.getClass() + " is not marked as a valid text field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Element asElement() {
|
||||||
|
return (Element) textField;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getText() {
|
||||||
|
switch (textField) {
|
||||||
|
case SpruceTextFieldWidget spruceTextField -> {
|
||||||
|
return spruceTextField.getText();
|
||||||
|
}
|
||||||
|
case TextFieldWidget vanillaTextField -> {
|
||||||
|
return vanillaTextField.getText();
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setText(String text) {
|
||||||
|
switch (textField) {
|
||||||
|
case SpruceTextFieldWidget spruceTextField -> {
|
||||||
|
spruceTextField.setText(text);
|
||||||
|
}
|
||||||
|
case TextFieldWidget vanillaTextField -> {
|
||||||
|
vanillaTextField.setText(text);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isMouseOver(double mouseX, double mouseY) {
|
||||||
|
switch (textField) {
|
||||||
|
case SpruceTextFieldWidget spruceTextField -> {
|
||||||
|
return spruceTextField.isMouseOver(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
case TextFieldWidget vanillaTextField -> {
|
||||||
|
return vanillaTextField.isMouseOver(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFocused() {
|
||||||
|
switch (textField) {
|
||||||
|
case SpruceTextFieldWidget spruceTextField -> {
|
||||||
|
return spruceTextField.isFocused();
|
||||||
|
}
|
||||||
|
case TextFieldWidget vanillaTextField -> {
|
||||||
|
return vanillaTextField.isFocused();
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isValidTextField(Object textField) {
|
||||||
|
return textField instanceof TextFieldWidget || textField instanceof SpruceTextFieldWidget;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user