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 inputText; private Sprite backgroundSprite; private int cursorPosition; // カーソル位置 private boolean showCursor; // カーソルの表示フラグ private float cursorBlinkTimer; // カーソルの点滅タイマー private final float CURSOR_BLINK_INTERVAL = 0.5f; // カーソルの点滅間隔(秒) private Color defaultColor; private Color focusColor; 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.inputText = ""; 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); defaultColor = new Color(1, 1, 1, 1); // 通常時の色 focusColor = new Color(0.7f, 0.7f, 0.7f, 1); // フォーカス中の色 displayText.setColor(defaultColor); } public void update() { handleInput(); updateCursorBlink(Time.deltaTime); render(); } private void handleInput() { float mouseX = MouseInput.getX(); float mouseY = MouseInput.getY(); if (Input.GetMouseButtonDown(GLFW_MOUSE_BUTTON_LEFT)) { isFocused = isMouseOver(mouseX, mouseY); if (isFocused) { setCursorPositionAtMouse(mouseX); displayText.setColor(focusColor); // フォーカス中は色を薄く } else { displayText.setColor(defaultColor); // フォーカスが外れたら元の色 } } if (isFocused) { handleTextInput(); if (Input.GetKeyDown(GLFW_KEY_ENTER)) { isFocused = false; // Enterで確定 displayText.setColor(defaultColor); // 色をリセット } if (Input.GetKeyDown(GLFW_KEY_BACKSPACE) && cursorPosition > 0) { inputText = inputText.substring(0, cursorPosition - 1) + inputText.substring(cursorPosition); cursorPosition--; displayText.setText(inputText.isEmpty() ? placeholder : inputText); } } } 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); // シフトキーで大文字、小文字切り替え inputText = inputText.substring(0, cursorPosition) + typedChar + inputText.substring(cursorPosition); cursorPosition++; displayText.setText(inputText.isEmpty() ? placeholder : inputText); } } // 数字入力 (メインの数字キー 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)); inputText = inputText.substring(0, cursorPosition) + typedChar + inputText.substring(cursorPosition); cursorPosition++; displayText.setText(inputText.isEmpty() ? placeholder : inputText); } } // テンキーの数字入力 (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)); inputText = inputText.substring(0, cursorPosition) + typedChar + inputText.substring(cursorPosition); cursorPosition++; displayText.setText(inputText.isEmpty() ? placeholder : inputText); } } // 記号入力(上手くいったもののみ) 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 < inputText.length()) { inputText = inputText.substring(0, cursorPosition) + inputText.substring(cursorPosition + 1); displayText.setText(inputText.isEmpty() ? placeholder : inputText); } // 左右キーでカーソル移動 if (Input.GetKeyDown(GLFW_KEY_LEFT) && cursorPosition > 0) { cursorPosition--; } if (Input.GetKeyDown(GLFW_KEY_RIGHT) && cursorPosition < inputText.length()) { cursorPosition++; } } private void appendChar(char c) { inputText = inputText.substring(0, cursorPosition) + c + inputText.substring(cursorPosition); cursorPosition++; displayText.setText(inputText.isEmpty() ? placeholder : inputText); } 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 = inputText.length(); } else { float cumulativeWidth = 0; for (int i = 0; i < inputText.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.update(); if (isFocused && showCursor) { float cursorX = position.x + displayText.getWidthAtIndex(cursorPosition); float cursorHeight = displayText.getDisplayedHeight(); Sprite sprite = new Sprite(Window.resourcePath + "button.png", cursorX, position.y, 1, 1); sprite.setSize(2, height); sprite.update(); } } }