package gameEngine.views; import gameEngine.Time; import gameEngine.input.MouseInput; import org.joml.Vector3f; import gameEngine.input.Input; import static org.lwjgl.glfw.GLFW.*; public class InputField implements IUpdatable { private Text displayText; private boolean isFocused; private Vector3f position; private float width, height; private String placeholder; private String currentText; // 入力中のテキスト private String displayedText; // 表示するテキスト private Sprite backgroundSprite; private int cursorPosition; // カーソル位置 private boolean showCursor; // カーソルの表示フラグ private float cursorBlinkTimer; // カーソルの点滅タイマー private final float CURSOR_BLINK_INTERVAL = 0.5f; // カーソルの点滅間隔(秒) private Color defaultColor; private OnChangeListener onChangeListener; public interface OnChangeListener { void onChange(String newValue); } public InputField(float posX, float posY, float width, float height, String placeholder, int textSize) { this.position = new Vector3f(posX, posY, 0); this.width = width; this.height = height; this.placeholder = placeholder; this.currentText = ""; this.displayedText = ""; this.isFocused = false; this.cursorPosition = 0; this.showCursor = true; this.cursorBlinkTimer = 0.0f; this.backgroundSprite = new Sprite(Window.resourcePath + "EditorFrame.png", posX, posY, width, height); this.backgroundSprite.setSize(width, height); displayText = new Text(posX + 2, posY, placeholder, textSize); displayText.setText(displayedText.isEmpty() ? placeholder : displayedText); displayText.setColor(new Color(1,1,1,1)); // RGB値 (白) } public void setOnChangeListener(OnChangeListener listener) { this.onChangeListener = listener; } public void update() { handleInput(); updateCursorBlink(Time.deltaTime); render(); } private void handleInput() { float mouseX = MouseInput.getX(); float mouseY = MouseInput.getY(); if (!isFocused && !currentText.equals(displayedText)) { currentText = displayedText; } if (Input.GetMouseButtonDown(GLFW_MOUSE_BUTTON_LEFT)) { boolean wasFocused = isFocused; isFocused = isMouseOver(mouseX, mouseY); if (!isFocused && wasFocused && onChangeListener != null) { displayedText = currentText; // 最終的な入力内容を更新 onChangeListener.onChange(currentText); } } if (isFocused) { handleTextInput(); if (Input.GetKeyDown(GLFW_KEY_ENTER)) { // Enterキーでフォーカス解除&内容を確定 isFocused = false; displayedText = currentText; // 入力内容を確定 if (onChangeListener != null) { onChangeListener.onChange(currentText); } } if (Input.GetKeyDown(GLFW_KEY_BACKSPACE) && cursorPosition > 0) { currentText = currentText.substring(0, cursorPosition - 1) + currentText.substring(cursorPosition); cursorPosition--; } } } private void handleTextInput() { boolean isShiftPressed = Input.GetKey(GLFW_KEY_LEFT_SHIFT) || Input.GetKey(GLFW_KEY_RIGHT_SHIFT); // 英字入力 for (int key = GLFW_KEY_A; key <= GLFW_KEY_Z; key++) { if (Input.GetKeyDown(key)) { char typedChar = (char) (isShiftPressed ? key : key + 32); // シフトキーで大文字・小文字切り替え currentText = currentText.substring(0, cursorPosition) + typedChar + currentText.substring(cursorPosition); cursorPosition++; } } // 数字入力 (メインの数字キー 0-9) for (int key = GLFW_KEY_0; key <= GLFW_KEY_9; key++) { if (Input.GetKeyDown(key)) { char typedChar = (char) ('0' + (key - GLFW_KEY_0)); currentText = currentText.substring(0, cursorPosition) + typedChar + currentText.substring(cursorPosition); cursorPosition++; displayText.setText(currentText.isEmpty() ? placeholder : currentText); } } // テンキーの数字入力 (0-9) for (int key = GLFW_KEY_KP_0; key <= GLFW_KEY_KP_9; key++) { if (Input.GetKeyDown(key)) { char typedChar = (char) ('0' + (key - GLFW_KEY_KP_0)); currentText = currentText.substring(0, cursorPosition) + typedChar + currentText.substring(cursorPosition); cursorPosition++; displayText.setText(currentText.isEmpty() ? placeholder : currentText); } } // 記号入力(上手くいったもののみ) if (isShiftPressed) { if (Input.GetKeyDown(GLFW_KEY_MINUS)) appendChar('='); else if (Input.GetKeyDown(GLFW_KEY_SEMICOLON)) appendChar('+'); else if (Input.GetKeyDown(GLFW_KEY_COMMA)) appendChar('<'); else if (Input.GetKeyDown(GLFW_KEY_PERIOD)) appendChar('>'); else if (Input.GetKeyDown(GLFW_KEY_SLASH)) appendChar('?'); } else { if (Input.GetKeyDown(GLFW_KEY_MINUS)) appendChar('-'); else if (Input.GetKeyDown(GLFW_KEY_SEMICOLON)) appendChar(';'); else if (Input.GetKeyDown(GLFW_KEY_COMMA)) appendChar(','); else if (Input.GetKeyDown(GLFW_KEY_PERIOD)) appendChar('.'); else if (Input.GetKeyDown(GLFW_KEY_SLASH)) appendChar('/'); } // Deleteキーでカーソル右側の文字を削除 if (Input.GetKeyDown(GLFW_KEY_DELETE) && cursorPosition < currentText.length()) { currentText = currentText.substring(0, cursorPosition) + currentText.substring(cursorPosition + 1); displayText.setText(currentText.isEmpty() ? placeholder : currentText); } // 左右キーでカーソル移動 if (Input.GetKeyDown(GLFW_KEY_LEFT) && cursorPosition > 0) { cursorPosition--; } if (Input.GetKeyDown(GLFW_KEY_RIGHT) && cursorPosition < currentText.length()) { cursorPosition++; } } private void appendChar(char c) { currentText = currentText.substring(0, cursorPosition) + c + currentText.substring(cursorPosition); cursorPosition++; displayText.setText(currentText.isEmpty() ? placeholder : currentText); } private void updateCursorBlink(float deltaTime) { cursorBlinkTimer += deltaTime; if (cursorBlinkTimer > CURSOR_BLINK_INTERVAL) { cursorBlinkTimer = 0.0f; showCursor = !showCursor; } } private void setCursorPositionAtMouse(float mouseX) { float relativeMouseX = mouseX - position.x; if (relativeMouseX <= 0) { cursorPosition = 0; } else if (relativeMouseX >= displayText.getDisplayedWidth()) { cursorPosition = currentText.length(); } else { float cumulativeWidth = 0; for (int i = 0; i < currentText.length(); i++) { cumulativeWidth += displayText.getWidthAtIndex(i); // 各文字の幅を取得 if (cumulativeWidth >= relativeMouseX) { cursorPosition = i; // 最も近い文字位置 break; } } } } public boolean isMouseOver(float mouseX, float mouseY) { return mouseX >= position.x && mouseX <= position.x + width && mouseY >= position.y && mouseY <= position.y + height; } public void render() { backgroundSprite.update(); displayText.setText(isFocused ? currentText : (displayedText.isEmpty() ? placeholder : displayedText)); displayText.update(); if (isFocused && showCursor) { float cursorX = position.x + displayText.getWidthAtIndex(cursorPosition); Text cursor = new Text(cursorX, position.y, "|", displayText.textSize); cursor.setColor(new Color(1,1,1,1)); // RGB値 (白) cursor.update(); } } public void copyDisplayedTextToCurrent(){ currentText = displayedText; } public void setText(String text) { this.displayedText = text; if (!isFocused) { displayText.setText(displayedText.isEmpty() ? placeholder : displayedText); } } }