Package tripleplay.platform

Source Code of tripleplay.platform.JavaNativeTextField

//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011-2014, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.platform;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;

import pythagoras.f.FloatMath;

import playn.core.Font;
import playn.core.Key;
import playn.core.PlayN;
import playn.java.JavaKeyboard;

import react.Connection;
import react.Slot;
import tripleplay.ui.Field;
import tripleplay.ui.Style;

import static tripleplay.platform.JavaTPPlatform.*;

public class JavaNativeTextField extends JavaNativeOverlay
    implements NativeTextField
{
    public static Class<? extends JTextComponent> resolveComponentType (Field.Native elem) {
        return elem.resolveStyle(Field.MULTILINE) ? JTextArea.class :
            elem.resolveStyle(Field.SECURE_TEXT_ENTRY) ? JPasswordField.class : JTextField.class;
    }

    public static JTextComponent create (Class<? extends JTextComponent> type) {
        try {
            return type.newInstance();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public JavaNativeTextField (Field.Native element) {
        this(element, null, resolveComponentType(element));
    }

    public JavaNativeTextField (Field.Native element, JavaNativeTextField oldField,
            Class<? extends JTextComponent> type) {
        super(create(type));
        _element = element;
        _textComp = (JTextComponent)component;

        if (oldField != null) {
            // reach in and disconnect the old field
            oldField._textConnection.disconnect();
            // copy bounds of old field
            component.setBounds(oldField.component.getBounds());
        }

        _textComp.setText(element.field().text.get());
        _textComp.getDocument().addDocumentListener(new DocumentListener() {
            public void changedUpdate (DocumentEvent event) {
                update();
            }
            public void insertUpdate (DocumentEvent event) {
                update();
            }
            public void removeUpdate (DocumentEvent event) {
                update();
            }
            protected void update () {
                if (!_textNotifyInProgress)
                    updateOnMainThread(_element.field().text, _textComp.getText());
            }
        });
        if (isField()) {
            asField().addActionListener(new ActionListener() {
                public void actionPerformed (ActionEvent event) {
                    emitOnMainThread(_element.finishedEditing(), true);
                }
            });
        }
        _textComp.addFocusListener(new FocusListener() {
            @Override public void focusGained (FocusEvent e) {
                updateOnMainThread(instance()._focus, _element.field());
            }
            @Override public void focusLost (FocusEvent e) {
                JavaTPPlatform.emitOnMainThread(_element.finishedEditing(), false);
                Component opposite = e.getOppositeComponent();
                if (opposite == null || !hasOverlayFor(opposite))
                    updateOnMainThread(instance()._focus, null);
            }
        });
        _textComp.addKeyListener(new KeyListener() {
            void post (Key key, boolean pressed, char typed) {
                // no need to hop threads here, the JavaKeyboard does that
                ((JavaKeyboard)PlayN.keyboard()).post(key, pressed, typed);
            }
            @Override public void keyTyped (KeyEvent e) {
                post(null, false, e.getKeyChar());
            }

            @Override public void keyReleased (KeyEvent e) {
                post(translateKeyCode(e.getKeyCode()), false, '\u0000');
            }

            @Override public void keyPressed (KeyEvent e) {
                post(translateKeyCode(e.getKeyCode()), true, '\u0000');
            }
        });

        // this should cause the field to have no background, but isn't working
        // TODO: figure out how to *really* not draw a white box underneath the field
        _textComp.setOpaque(false);

        _textComp.setBorder(null);
        _textComp.setAutoscrolls(true);

        _textConnection = _element.field().text.connectNotify(new Slot<String>() {
            @Override public void onEmit (final String value) {
                EventQueue.invokeLater(new Runnable() {
                    @Override public void run () {
                        if (!_textComp.getText().equals(value)) {
                            _textNotifyInProgress = true;
                            _textComp.setText(value);
                            _textNotifyInProgress = false;
                        }
                    }
                });
            }});
    }

    /** Re-applies the current Field styles to the text component. */
    public void validateStyles () {
        Font font = _element.resolveStyle(Style.FONT);
        _textComp.setFont(new java.awt.Font(font.name(), awtFontStyle(font.style()),
            FloatMath.round(font.size())));
        Color col = new Color(_element.resolveStyle(Style.COLOR));
        _textComp.setForeground(col);
        _textComp.setCaretColor(col);

        if (isField()) {
            switch (_element.resolveStyle(Style.HALIGN)) {
            case CENTER:
                asField().setHorizontalAlignment(JTextField.CENTER);
                break;
            case LEFT:
                asField().setHorizontalAlignment(JTextField.LEFT);
                break;
            case RIGHT:
                asField().setHorizontalAlignment(JTextField.RIGHT);
                break;
            }
        }

        // TODO: Keyboard.TextType textType = resolveStyle(Field.TEXT_TYPE);
    }

    @Override
    public void setEnabled (boolean enabled) {
        _textComp.setEnabled(enabled);
    }

    public JavaNativeTextField refresh () {
        Class<? extends JTextComponent> type = resolveComponentType(_element);
        return type == component.getClass() ? this : new JavaNativeTextField(_element, this, type);
    }

    @Override public void focus () {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run () { _textComp.requestFocusInWindow(); }
        });
    }

    @Override public boolean insert (String text) {
        _textComp.replaceSelection(text);
        return true;
    }

    protected boolean isField () {
        return _textComp instanceof JTextField;
    }

    protected JTextField asField () {
        return (JTextField)_textComp;
    }

    protected static int awtFontStyle (Font.Style style) {
        switch (style) {
        case BOLD: return java.awt.Font.BOLD;
        case BOLD_ITALIC: return java.awt.Font.BOLD | java.awt.Font.ITALIC;
        case ITALIC: return java.awt.Font.ITALIC;
        case PLAIN: return java.awt.Font.PLAIN;
        }

        // Unknown style, use plain.
        return java.awt.Font.PLAIN;
    }

    /** Translates an AWT key code into a playn key, if possible. May return {@link Key#UNKNOWN} if
     * there is no translation. */
    protected static Key translateKeyCode (int code) {
        switch (code) {
            case KeyEvent.VK_ENTER: return Key.ENTER;
            case KeyEvent.VK_BACK_SPACE: return Key.BACKSPACE;
            case KeyEvent.VK_TAB: return Key.TAB;
            case KeyEvent.VK_CANCEL: return Key.UNKNOWN;
            case KeyEvent.VK_CLEAR: return Key.UNKNOWN;
            case KeyEvent.VK_SHIFT: return Key.SHIFT;
            case KeyEvent.VK_CONTROL: return Key.CONTROL;
            case KeyEvent.VK_ALT: return Key.ALT;
            case KeyEvent.VK_PAUSE: return Key.PAUSE;
            case KeyEvent.VK_CAPS_LOCK: return Key.CAPS_LOCK;
            case KeyEvent.VK_ESCAPE: return Key.ESCAPE;
            case KeyEvent.VK_SPACE: return Key.SPACE;
            case KeyEvent.VK_PAGE_UP: return Key.PAGE_UP;
            case KeyEvent.VK_PAGE_DOWN: return Key.PAGE_DOWN;
            case KeyEvent.VK_END: return Key.END;
            case KeyEvent.VK_HOME: return Key.HOME;
            case KeyEvent.VK_LEFT: return Key.LEFT;
            case KeyEvent.VK_UP: return Key.UP;
            case KeyEvent.VK_RIGHT: return Key.RIGHT;
            case KeyEvent.VK_DOWN: return Key.DOWN;
            case KeyEvent.VK_COMMA: return Key.COMMA;
            case KeyEvent.VK_MINUS: return Key.MINUS;
            case KeyEvent.VK_PERIOD: return Key.PERIOD;
            case KeyEvent.VK_SLASH: return Key.SLASH;
            case KeyEvent.VK_0: return Key.K0;
            case KeyEvent.VK_1: return Key.K1;
            case KeyEvent.VK_2: return Key.K2;
            case KeyEvent.VK_3: return Key.K3;
            case KeyEvent.VK_4: return Key.K4;
            case KeyEvent.VK_5: return Key.K5;
            case KeyEvent.VK_6: return Key.K6;
            case KeyEvent.VK_7: return Key.K7;
            case KeyEvent.VK_8: return Key.K8;
            case KeyEvent.VK_9: return Key.K9;
            case KeyEvent.VK_SEMICOLON: return Key.SEMICOLON;
            case KeyEvent.VK_EQUALS: return Key.EQUALS;
            case KeyEvent.VK_A: return Key.A;
            case KeyEvent.VK_B: return Key.B;
            case KeyEvent.VK_C: return Key.C;
            case KeyEvent.VK_D: return Key.D;
            case KeyEvent.VK_E: return Key.E;
            case KeyEvent.VK_F: return Key.F;
            case KeyEvent.VK_G: return Key.G;
            case KeyEvent.VK_H: return Key.H;
            case KeyEvent.VK_I: return Key.I;
            case KeyEvent.VK_J: return Key.J;
            case KeyEvent.VK_K: return Key.K;
            case KeyEvent.VK_L: return Key.L;
            case KeyEvent.VK_M: return Key.M;
            case KeyEvent.VK_N: return Key.N;
            case KeyEvent.VK_O: return Key.O;
            case KeyEvent.VK_P: return Key.P;
            case KeyEvent.VK_Q: return Key.Q;
            case KeyEvent.VK_R: return Key.R;
            case KeyEvent.VK_S: return Key.S;
            case KeyEvent.VK_T: return Key.T;
            case KeyEvent.VK_U: return Key.U;
            case KeyEvent.VK_V: return Key.V;
            case KeyEvent.VK_W: return Key.W;
            case KeyEvent.VK_X: return Key.X;
            case KeyEvent.VK_Y: return Key.Y;
            case KeyEvent.VK_Z: return Key.Z;
            case KeyEvent.VK_OPEN_BRACKET: return Key.LEFT_BRACKET;
            case KeyEvent.VK_BACK_SLASH: return Key.BACKSLASH;
            case KeyEvent.VK_CLOSE_BRACKET: return Key.RIGHT_BRACKET;
            case KeyEvent.VK_NUMPAD0: return Key.NP0;
            case KeyEvent.VK_NUMPAD1: return Key.NP1;
            case KeyEvent.VK_NUMPAD2: return Key.NP2;
            case KeyEvent.VK_NUMPAD3: return Key.NP3;
            case KeyEvent.VK_NUMPAD4: return Key.NP4;
            case KeyEvent.VK_NUMPAD5: return Key.NP5;
            case KeyEvent.VK_NUMPAD6: return Key.NP6;
            case KeyEvent.VK_NUMPAD7: return Key.NP7;
            case KeyEvent.VK_NUMPAD8: return Key.NP8;
            case KeyEvent.VK_NUMPAD9: return Key.NP9;
            case KeyEvent.VK_MULTIPLY: return Key.MULTIPLY;
            case KeyEvent.VK_ADD: return Key.NP_ADD;
            case KeyEvent.VK_SEPARATOR: return Key.UNKNOWN;
            case KeyEvent.VK_SUBTRACT: return Key.NP_SUBTRACT;
            case KeyEvent.VK_DECIMAL: return Key.NP_DECIMAL;
            case KeyEvent.VK_DIVIDE: return Key.NP_DIVIDE;
            case KeyEvent.VK_DELETE: return Key.DELETE;
            case KeyEvent.VK_NUM_LOCK: return Key.NP_NUM_LOCK;
            case KeyEvent.VK_SCROLL_LOCK: return Key.SCROLL_LOCK;
            case KeyEvent.VK_F1: return Key.F1;
            case KeyEvent.VK_F2: return Key.F2;
            case KeyEvent.VK_F3: return Key.F3;
            case KeyEvent.VK_F4: return Key.F4;
            case KeyEvent.VK_F5: return Key.F5;
            case KeyEvent.VK_F6: return Key.F6;
            case KeyEvent.VK_F7: return Key.F7;
            case KeyEvent.VK_F8: return Key.F8;
            case KeyEvent.VK_F9: return Key.F9;
            case KeyEvent.VK_F10: return Key.F10;
            case KeyEvent.VK_F11: return Key.F11;
            case KeyEvent.VK_F12: return Key.F12;
            /* omitted cases for F13-F24, these are not standard */
            case KeyEvent.VK_PRINTSCREEN: return Key.PRINT_SCREEN;
            case KeyEvent.VK_INSERT: return Key.INSERT;
            case KeyEvent.VK_HELP: return Key.UNKNOWN;
            case KeyEvent.VK_META: return Key.META;
            case KeyEvent.VK_BACK_QUOTE: return Key.BACKQUOTE;
            case KeyEvent.VK_QUOTE: return Key.QUOTE;
            case KeyEvent.VK_KP_UP: return Key.NP_UP;
            case KeyEvent.VK_KP_DOWN: return Key.NP_DOWN;
            case KeyEvent.VK_KP_LEFT: return Key.NP_LEFT;
            case KeyEvent.VK_KP_RIGHT: return Key.NP_RIGHT;
            case KeyEvent.VK_AMPERSAND: return Key.AMPERSAND;
            case KeyEvent.VK_ASTERISK: return Key.ASTERISK;
            case KeyEvent.VK_QUOTEDBL: return Key.DOUBLE_QUOTE;
            case KeyEvent.VK_LESS: return Key.LESS;
            case KeyEvent.VK_GREATER: return Key.GREATER;
            case KeyEvent.VK_BRACELEFT: return Key.LEFT_BRACE;
            case KeyEvent.VK_BRACERIGHT: return Key.RIGHT_BRACE;
            case KeyEvent.VK_AT: return Key.AT;
            case KeyEvent.VK_COLON: return Key.COLON;
            case KeyEvent.VK_CIRCUMFLEX: return Key.CIRCUMFLEX;
            case KeyEvent.VK_DOLLAR: return Key.DOLLAR;
            case KeyEvent.VK_LEFT_PARENTHESIS: return Key.LEFT_PAREN;
            case KeyEvent.VK_EXCLAMATION_MARK: return Key.BANG;
            case KeyEvent.VK_NUMBER_SIGN: return Key.HASH;
            case KeyEvent.VK_PLUS: return Key.PLUS;
            case KeyEvent.VK_RIGHT_PARENTHESIS: return Key.RIGHT_PAREN;
            case KeyEvent.VK_UNDERSCORE: return Key.UNDERSCORE;
            case KeyEvent.VK_WINDOWS: return Key.WINDOWS;
            // case KeyEvent.VK_CONTEXT_MENU: return Key.CONTEXT_MENU;
            // TODO: "Edit menu" keys in playn?
            // case KeyEvent.VK_CUT: return Key.CUT;
            // case KeyEvent.VK_COPY: return Key.COPY;
            // case KeyEvent.VK_PASTE: return Key.PASTE;
            // case KeyEvent.VK_UNDO: return Key.UNDO;
            // case KeyEvent.VK_AGAIN: return Key.AGAIN;
            // case KeyEvent.VK_FIND: return Key.FIND;
            // case KeyEvent.VK_PROPS: return Key.PROPS;
            // case KeyEvent.VK_STOP: return Key.STOP;
            // case KeyEvent.VK_COMPOSE: return Key.COMPOSE;
            // case KeyEvent.VK_ALT_GRAPH: return Key.ALT_GRAPH;
            // case KeyEvent.VK_BEGIN: return Key.BEGIN;
            // TODO: European keyboard support in playn?
            // case KeyEvent.VK_DEAD_GRAVE: return Key.DEAD_GRAVE;
            // case KeyEvent.VK_DEAD_ACUTE: return Key.DEAD_ACUTE;
            // case KeyEvent.VK_DEAD_CIRCUMFLEX: return Key.DEAD_CIRCUMFLEX;
            // case KeyEvent.VK_DEAD_TILDE: return Key.DEAD_TILDE;
            // case KeyEvent.VK_DEAD_MACRON: return Key.DEAD_MACRON;
            // case KeyEvent.VK_DEAD_BREVE: return Key.DEAD_BREVE;
            // case KeyEvent.VK_DEAD_ABOVEDOT: return Key.DEAD_ABOVEDOT;
            // case KeyEvent.VK_DEAD_DIAERESIS: return Key.DEAD_DIAERESIS;
            // case KeyEvent.VK_DEAD_ABOVERING: return Key.DEAD_ABOVERING;
            // case KeyEvent.VK_DEAD_DOUBLEACUTE: return Key.DEAD_DOUBLEACUTE;
            // case KeyEvent.VK_DEAD_CARON: return Key.DEAD_CARON;
            // case KeyEvent.VK_DEAD_CEDILLA: return Key.DEAD_CEDILLA;
            // case KeyEvent.VK_DEAD_OGONEK: return Key.DEAD_OGONEK;
            // case KeyEvent.VK_DEAD_IOTA: return Key.DEAD_IOTA;
            // case KeyEvent.VK_DEAD_VOICED_SOUND: return Key.DEAD_VOICED_SOUND;
            // case KeyEvent.VK_DEAD_SEMIVOICED_SOUND: return Key.DEAD_SEMIVOICED_SOUND;
            // case KeyEvent.VK_EURO_SIGN: return Key.EURO_SIGN;
            // case KeyEvent.VK_INVERTED_EXCLAMATION_MARK: return Key.INVERTED_EXCLAMATION_MARK;
            // TODO: support asian keyboards in playn?
            // case KeyEvent.VK_FINAL: return Key.FINAL;
            // case KeyEvent.VK_CONVERT: return Key.CONVERT;
            // case KeyEvent.VK_NONCONVERT: return Key.NONCONVERT;
            // case KeyEvent.VK_ACCEPT: return Key.ACCEPT;
            // case KeyEvent.VK_MODECHANGE: return Key.MODECHANGE;
            // case KeyEvent.VK_KANA: return Key.KANA;
            // case KeyEvent.VK_KANJI: return Key.KANJI;
            // case KeyEvent.VK_ALPHANUMERIC: return Key.ALPHANUMERIC;
            // case KeyEvent.VK_KATAKANA: return Key.KATAKANA;
            // case KeyEvent.VK_HIRAGANA: return Key.HIRAGANA;
            // case KeyEvent.VK_FULL_WIDTH: return Key.FULL_WIDTH;
            // case KeyEvent.VK_HALF_WIDTH: return Key.HALF_WIDTH;
            // case KeyEvent.VK_ROMAN_CHARACTERS: return Key.ROMAN_CHARACTERS;
            // case KeyEvent.VK_ALL_CANDIDATES: return Key.ALL_CANDIDATES;
            // case KeyEvent.VK_PREVIOUS_CANDIDATE: return Key.PREVIOUS_CANDIDATE;
            // case KeyEvent.VK_CODE_INPUT: return Key.CODE_INPUT;
            // case KeyEvent.VK_JAPANESE_KATAKANA: return Key.JAPANESE_KATAKANA;
            // case KeyEvent.VK_JAPANESE_HIRAGANA: return Key.JAPANESE_HIRAGANA;
            // case KeyEvent.VK_JAPANESE_ROMAN: return Key.JAPANESE_ROMAN;
            // case KeyEvent.VK_KANA_LOCK: return Key.KANA_LOCK;
            // case KeyEvent.VK_INPUT_METHOD_ON_OFF: return Key.INPUT_METHOD_ON_OFF;
            default: return Key.UNKNOWN;
        }
    }

    protected final Field.Native _element;
    protected final JTextComponent _textComp;

    protected Connection _textConnection;
    protected volatile boolean _textNotifyInProgress;
}
TOP

Related Classes of tripleplay.platform.JavaNativeTextField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.