Newer
Older
AlgebraicDataflowArchitectureModel / GameEngine / src / main / java / gameEngine / views / InputField.java
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();
        }
    }
}