package com.game.framework.display.ui; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Widget; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Clipboard; import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.Timer.Task; public class TextArea extends Widget { static private final char BACKSPACE = 8; static private final char ENTER_DESKTOP = '\r'; static private final char ENTER_ANDROID = '\n'; static private final char TAB = '\t'; static private final char DELETE = 127; static private final char BULLET = 149; static private final Vector2 tmp1 = new Vector2(); static private final Vector2 tmp2 = new Vector2(); static private final Vector2 tmp3 = new Vector2(); TextAreaStyle style; String text, messageText; private CharSequence displayText; int cursor; private Clipboard clipboard; TextAreaListener listener; TextAreaFilter filter; OnscreenKeyboard keyboard = new DefaultOnscreenKeyboard(); boolean focusTraversal = true; boolean disabled; boolean onlyFontChars = true; private boolean passwordMode; private StringBuilder passwordBuffer; private final Rectangle fieldBounds = new Rectangle(); private final TextBounds textBounds = new TextBounds(); private final Rectangle scissor = new Rectangle(); float renderOffset, textOffset; private int visibleTextStart, visibleTextEnd; private final FloatArray glyphAdvances = new FloatArray(); final FloatArray glyphPositions = new FloatArray(); boolean cursorOn = true; private float blinkTime = 0.32f; long lastBlink; boolean hasSelection; int selectionStart; private float selectionX, selectionWidth; private char passwordCharacter = BULLET; InputListener inputListener; KeyRepeatTask keyRepeatTask = new KeyRepeatTask(); float keyRepeatInitialTime = 0.4f; float keyRepeatTime = 0.1f; boolean rightAligned; int maxLength = 0; private float displayTextY; public TextArea (String text, Skin skin) { this(text, skin.get(TextAreaStyle.class)); } public TextArea (String text, Skin skin, String styleName) { this(text, skin.get(styleName, TextAreaStyle.class)); } public TextArea (String text, TextAreaStyle style) { setStyle(style); this.clipboard = Gdx.app.getClipboard(); setText(text); setWidth(getPrefWidth()); setHeight(getPrefHeight()); initialize(); } private void initialize () { addListener(inputListener = new ClickListener() { public void clicked (InputEvent event, float x, float y) { if(disabled) return; if (getTapCount() > 1) setSelection(0, text.length()); } public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { if(disabled) return false; if (getTapCount() > 1) if (!super.touchDown(event, x, y, pointer, button)) return false; if (pointer == 0 && button != 0) return false; if (disabled) return true; clearSelection(); setCursorPosition(x); selectionStart = cursor; Stage stage = getStage(); if (stage != null) stage.setKeyboardFocus(TextArea.this); keyboard.show(true); return true; } public void touchDragged (InputEvent event, float x, float y, int pointer) { super.touchDragged(event, x, y, pointer); if(disabled) return; if (getTapCount() > 1) lastBlink = 0; cursorOn = false; setCursorPosition(x); hasSelection = true; } private void setCursorPosition (float x) { lastBlink = 0; cursorOn = false; x -= renderOffset + textOffset; for (int i = 0; i < glyphPositions.size; i++) { if (glyphPositions.items[i] > x) { cursor = Math.max(0, i - 1); return; } } cursor = Math.max(0, glyphPositions.size - 1); } public boolean keyDown (InputEvent event, int keycode) { if (disabled) return false; final BitmapFont font = style.font; lastBlink = 0; cursorOn = false; Stage stage = getStage(); if (stage != null && stage.getKeyboardFocus() == TextArea.this) { boolean repeat = false; boolean ctrl = Gdx.input.isKeyPressed(Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Keys.CONTROL_RIGHT); if (ctrl) { // paste if (keycode == Keys.V) { paste(); return true; } // copy if (keycode == Keys.C || keycode == Keys.INSERT) { copy(); return true; } // cut if (keycode == Keys.X || keycode == Keys.DEL) { cut(); return true; } } if (Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT)) { // paste if (keycode == Keys.INSERT) paste(); // cut if (keycode == Keys.FORWARD_DEL) { if (hasSelection) { copy(); delete(); } } // selection if (keycode == Keys.LEFT) { if (!hasSelection) { selectionStart = cursor; hasSelection = true; } while (--cursor > 0 && ctrl) { char c = text.charAt(cursor); if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; break; } repeat = true; } if (keycode == Keys.RIGHT) { if (!hasSelection) { selectionStart = cursor; hasSelection = true; } int length = text.length(); while (++cursor < length && ctrl) { char c = text.charAt(cursor - 1); if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; break; } repeat = true; } if (keycode == Keys.HOME) { if (!hasSelection) { selectionStart = cursor; hasSelection = true; } cursor = 0; } if (keycode == Keys.END) { if (!hasSelection) { selectionStart = cursor; hasSelection = true; } cursor = text.length(); } cursor = Math.max(0, cursor); cursor = Math.min(text.length(), cursor); } else { // cursor movement or other keys (kill selection) if (keycode == Keys.LEFT) { while (cursor-- > 1 && ctrl) { char c = text.charAt(cursor - 1); if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; break; } clearSelection(); repeat = true; } if (keycode == Keys.RIGHT) { int length = text.length(); while (++cursor < length && ctrl) { char c = text.charAt(cursor - 1); if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; break; } clearSelection(); repeat = true; } if (keycode == Keys.HOME) { cursor = 0; clearSelection(); } if (keycode == Keys.END) { cursor = text.length(); clearSelection(); } cursor = Math.max(0, cursor); cursor = Math.min(text.length(), cursor); } if (repeat && (!keyRepeatTask.isScheduled() || keyRepeatTask.keycode != keycode)) { keyRepeatTask.keycode = keycode; keyRepeatTask.cancel(); Timer.schedule(keyRepeatTask, keyRepeatInitialTime, keyRepeatTime); } return true; } return false; } public boolean keyUp (InputEvent event, int keycode) { if (disabled) return false; keyRepeatTask.cancel(); return true; } public boolean keyTyped (InputEvent event, char character) { if (disabled) return false; final BitmapFont font = style.font; Stage stage = getStage(); if (stage != null && stage.getKeyboardFocus() == TextArea.this) { if (character == BACKSPACE) { if (cursor > 0 || hasSelection) { if (!hasSelection) { text = text.substring(0, cursor - 1) + text.substring(cursor); updateDisplayText(); cursor--; renderOffset = 0; } else { delete(); } } } else if (character == DELETE) { if (cursor < text.length() || hasSelection) { if (!hasSelection) { text = text.substring(0, cursor) + text.substring(cursor + 1); updateDisplayText(); } else { delete(); } } } else if ((character == TAB || character == ENTER_ANDROID) && focusTraversal) { next(Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT)); } else if (font.containsCharacter(character)) { // Character may be added to the text. if (character != ENTER_DESKTOP && character != ENTER_ANDROID) { if (filter != null && !filter.acceptChar(TextArea.this, character)) return true; } if (maxLength > 0 && text.length() + 1 > maxLength) return true; if (!hasSelection) { text = text.substring(0, cursor) + character + text.substring(cursor, text.length()); updateDisplayText(); cursor++; } else { int minIndex = Math.min(cursor, selectionStart); int maxIndex = Math.max(cursor, selectionStart); text = (minIndex > 0 ? text.substring(0, minIndex) : "") + (maxIndex < text.length() ? text.substring(maxIndex, text.length()) : ""); cursor = minIndex; text = text.substring(0, cursor) + character + text.substring(cursor, text.length()); updateDisplayText(); cursor++; clearSelection(); } } if (listener != null) listener.keyTyped(TextArea.this, character); return true; } else return false; } }); } public void setMaxLength (int maxLength) { this.maxLength = maxLength; } public int getMaxLength () { return this.maxLength; } /** When false, text set by {@link #setText(String)} may contain characters not in the font, a space will be displayed instead. * When true (the default), characters not in the font are stripped by setText. Characters not in the font are always stripped * when typed or pasted. */ public void setOnlyFontChars (boolean onlyFontChars) { this.onlyFontChars = onlyFontChars; } public void setStyle (TextAreaStyle style) { if (style == null) throw new IllegalArgumentException("style cannot be null."); this.style = style; invalidateHierarchy(); } /** Sets the password character for the text field. The character must be present in the {@link BitmapFont} */ public void setPasswordCharacter (char passwordCharacter) { this.passwordCharacter = passwordCharacter; if (passwordMode) updateDisplayText(); } /** Returns the text field's style. Modifying the returned style may not have an effect until {@link #setStyle(TextAreaStyle)} * is called. */ public TextAreaStyle getStyle () { return style; } /* private void calculateOffsets () { float visibleWidth = getWidth(); if (style.background != null) visibleWidth -= style.background.getLeftWidth() + style.background.getRightWidth(); // Check if the cursor has gone out the left or right side of the visible area and adjust renderoffset. float position = glyphPositions.get(cursor); float distance = position - Math.abs(renderOffset); if (distance <= 0) { if (cursor > 0) renderOffset = -glyphPositions.get(cursor - 1); else renderOffset = 0; } else if (distance > visibleWidth) { renderOffset -= distance - visibleWidth; } // calculate first visible char based on render offset visibleTextStart = 0; textOffset = 0; float start = Math.abs(renderOffset); int len = glyphPositions.size; float startPos = 0; for (int i = 0; i < len; i++) { if (glyphPositions.items[i] >= start) { visibleTextStart = i; startPos = glyphPositions.items[i]; textOffset = startPos - start; break; } } // calculate last visible char based on visible width and render offset visibleTextEnd = Math.min(displayText.length(), cursor + 1); for (; visibleTextEnd <= displayText.length(); visibleTextEnd++) { if (glyphPositions.items[visibleTextEnd] - startPos > visibleWidth) break; } visibleTextEnd = Math.max(0, visibleTextEnd - 1); // calculate selection x position and width if (hasSelection) { int minIndex = Math.min(cursor, selectionStart); int maxIndex = Math.max(cursor, selectionStart); float minX = Math.max(glyphPositions.get(minIndex), startPos); float maxX = Math.min(glyphPositions.get(maxIndex), glyphPositions.get(visibleTextEnd)); selectionX = minX; selectionWidth = maxX - minX; } if (rightAligned) { textOffset = visibleWidth - (glyphPositions.items[visibleTextEnd] - startPos); if (hasSelection) selectionX += textOffset; } } */ @Override public void draw (SpriteBatch batch, float parentAlpha) { Stage stage = getStage(); boolean focused = stage != null && stage.getKeyboardFocus() == this; final BitmapFont font = style.font; final Color fontColor = (disabled && style.disabledFontColor != null) ? style.disabledFontColor : ((focused && style.focusedFontColor != null) ? style.focusedFontColor : style.fontColor); final Drawable selection = style.selection; final Drawable cursorPatch = style.cursor; final Drawable background = (disabled && style.disabledBackground != null) ? style.disabledBackground : ((focused && style.focusedBackground != null) ? style.focusedBackground : style.background); Color color = getColor(); float x = getX(); float y = getY(); float width = getWidth(); float height = getHeight(); float textY = textBounds.height / 2 + font.getDescent(); batch.setColor(color.r, color.g, color.b, color.a * parentAlpha); float bgLeftWidth = 0; if (background != null) { background.draw(batch, x, y, width, height); bgLeftWidth = background.getLeftWidth(); float bottom = background.getBottomHeight(); textY = (int)(textY + (height - background.getTopHeight() - bottom ) ); } else textY = (int)(textY + height / 2); //calculateOffsets(); if (focused && hasSelection && selection != null) { selection.draw(batch, x + selectionX + bgLeftWidth + renderOffset, y + textY - textBounds.height - font.getDescent(), selectionWidth, textBounds.height + font.getDescent() / 2); } float yOffset = font.isFlipped() ? -textBounds.height : 0; if (displayText.length() == 0) { if (!focused && messageText != null) { if (style.messageFontColor != null) { font.setColor(style.messageFontColor.r, style.messageFontColor.g, style.messageFontColor.b, style.messageFontColor.a * parentAlpha); } else font.setColor(0.7f, 0.7f, 0.7f, parentAlpha); BitmapFont messageFont = style.messageFont != null ? style.messageFont : font; messageFont.draw(batch, messageText, x + bgLeftWidth, y + textY + yOffset); } } else { font.setColor(fontColor.r, fontColor.g, fontColor.b, fontColor.a * parentAlpha); //font.draw(batch, displayText, x + bgLeftWidth + textOffset, y + textY + yOffset, visibleTextStart, visibleTextEnd); font.drawWrapped(batch, displayText, x + bgLeftWidth + textOffset, y + textY + displayTextY + yOffset, getWidth(), HAlignment.LEFT); } if (focused && !disabled) { blink(); if (cursorOn && cursorPatch != null) { cursorPatch.draw(batch, x + bgLeftWidth + textOffset + glyphPositions.get(cursor) - glyphPositions.items[visibleTextStart] - 1, y + textY - textBounds.height - font.getDescent(), cursorPatch.getMinWidth(), textBounds.height + font.getDescent() / 2); } } } void updateDisplayText () { StringBuilder buffer = new StringBuilder(); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); buffer.append(style.font.containsCharacter(c) || c== '\n' ? c : ' '); } String text = buffer.toString(); if (passwordMode && style.font.containsCharacter(passwordCharacter)) { if (passwordBuffer == null) passwordBuffer = new StringBuilder(text.length()); if (passwordBuffer.length() > text.length()) // passwordBuffer.setLength(text.length()); else { for (int i = passwordBuffer.length(), n = text.length(); i < n; i++) passwordBuffer.append(passwordCharacter); } displayText = passwordBuffer; } else displayText = text; style.font.computeGlyphAdvancesAndPositions(displayText, glyphAdvances, glyphPositions); if (selectionStart > text.length()) selectionStart = text.length(); } private void blink () { long time = TimeUtils.nanoTime(); if ((time - lastBlink) / 1000000000.0f > blinkTime) { cursorOn = !cursorOn; lastBlink = time; } } /** Copies the contents of this TextArea to the {@link Clipboard} implementation set on this TextArea. */ public void copy () { if (hasSelection) { int minIndex = Math.min(cursor, selectionStart); int maxIndex = Math.max(cursor, selectionStart); clipboard.setContents(text.substring(minIndex, maxIndex)); } } /** Copies the selected contents of this TextArea to the {@link Clipboard} implementation set on this TextArea, then removes * it. */ public void cut () { if (hasSelection) { copy(); delete(); } } /** Pastes the content of the {@link Clipboard} implementation set on this TextArea to this TextArea. */ void paste () { String content = clipboard.getContents(); if (content != null) { StringBuilder buffer = new StringBuilder(); for (int i = 0; i < content.length(); i++) { if (maxLength > 0 && text.length() + buffer.length() + 1 > maxLength) break; char c = content.charAt(i); if (!style.font.containsCharacter(c)) continue; if (filter != null && !filter.acceptChar(this, c)) continue; buffer.append(c); } content = buffer.toString(); if (!hasSelection) { text = text.substring(0, cursor) + content + text.substring(cursor, text.length()); updateDisplayText(); cursor += content.length(); } else { int minIndex = Math.min(cursor, selectionStart); int maxIndex = Math.max(cursor, selectionStart); text = (minIndex > 0 ? text.substring(0, minIndex) : "") + (maxIndex < text.length() ? text.substring(maxIndex, text.length()) : ""); cursor = minIndex; text = text.substring(0, cursor) + content + text.substring(cursor, text.length()); updateDisplayText(); cursor = minIndex + content.length(); clearSelection(); } } } void delete () { int minIndex = Math.min(cursor, selectionStart); int maxIndex = Math.max(cursor, selectionStart); text = (minIndex > 0 ? text.substring(0, minIndex) : "") + (maxIndex < text.length() ? text.substring(maxIndex, text.length()) : ""); updateDisplayText(); cursor = minIndex; clearSelection(); } /** Focuses the next TextArea. If none is found, the keyboard is hidden. Does nothing if the text field is not in a stage. * @param up If true, the TextArea with the same or next smallest y coordinate is found, else the next highest. */ public void next (boolean up) { Stage stage = getStage(); if (stage == null) return; getParent().localToStageCoordinates(tmp1.set(getX(), getY())); TextArea textField = findNextTextArea(stage.getActors(), null, tmp2, tmp1, up); if (textField == null) { // Try to wrap around. if (up) tmp1.set(Float.MIN_VALUE, Float.MIN_VALUE); else tmp1.set(Float.MAX_VALUE, Float.MAX_VALUE); textField = findNextTextArea(getStage().getActors(), null, tmp2, tmp1, up); } if (textField != null) stage.setKeyboardFocus(textField); else Gdx.input.setOnscreenKeyboardVisible(false); } private TextArea findNextTextArea (Array<Actor> actors, TextArea best, Vector2 bestCoords, Vector2 currentCoords, boolean up) { for (int i = 0, n = actors.size; i < n; i++) { Actor actor = actors.get(i); if (actor == this) continue; if (actor instanceof TextArea) { TextArea textField = (TextArea)actor; if (textField.isDisabled() || !textField.focusTraversal) continue; Vector2 actorCoords = actor.getParent().localToStageCoordinates(tmp3.set(actor.getX(), actor.getY())); if ((actorCoords.y < currentCoords.y || (actorCoords.y == currentCoords.y && actorCoords.x > currentCoords.x)) ^ up) { if (best == null || (actorCoords.y > bestCoords.y || (actorCoords.y == bestCoords.y && actorCoords.x < bestCoords.x)) ^ up) { best = (TextArea)actor; bestCoords.set(actorCoords); } } } else if (actor instanceof Group) best = findNextTextArea(((Group)actor).getChildren(), best, bestCoords, currentCoords, up); } return best; } /** @param listener May be null. */ public void setTextAreaListener (TextAreaListener listener) { this.listener = listener; } /** @param filter May be null. */ public void setTextAreaFilter (TextAreaFilter filter) { this.filter = filter; } /** If true (the default), tab/shift+tab will move to the next text field. */ public void setFocusTraversal (boolean focusTraversal) { this.focusTraversal = focusTraversal; } /** @return May be null. */ public String getMessageText () { return messageText; } /** Sets the text that will be drawn in the text field if no text has been entered. * @param messageText may be null. */ public void setMessageText (String messageText) { this.messageText = messageText; } public void setText (String text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); BitmapFont font = style.font; StringBuilder buffer = new StringBuilder(); for (int i = 0; i < text.length(); i++) { if (maxLength > 0 && buffer.length() + 1 > maxLength) break; char c = text.charAt(i); if(c == '\n') { } else { if (onlyFontChars && !style.font.containsCharacter(c)) continue; if (filter != null && !filter.acceptChar(this, c)) continue; } buffer.append(c); } this.text = buffer.toString(); updateDisplayText(); cursor = 0; clearSelection(); textBounds.set(font.getBounds(displayText)); textBounds.height -= font.getDescent() * 2; font.computeGlyphAdvancesAndPositions(displayText, glyphAdvances, glyphPositions); TextBounds bounds = font.getWrappedBounds(displayText, getWidth() - textOffset); if(bounds.height > getHeight()) { float visibleHeight = getHeight(); float excessHeight = bounds.height - visibleHeight; float lineHeight = font.getLineHeight(); int ceil = (int)(Math.ceil(excessHeight/lineHeight)); //displayTextY = (ceil * lineHeight); int availableLines = (int)Math.ceil(visibleHeight / lineHeight); //get only the new append texts. String textToDisplay = ""; for(int i= displayText.length()-1;i >=0 ;i--) { char c = displayText.charAt(i); if(c == '\n') { availableLines--; if(availableLines==0) break; } textToDisplay = c + textToDisplay; } displayText = textToDisplay; } } private String chopChopText(String text) { // TODO Auto-generated method stub String scanedText= ""; String outputText = ""; for(int i=0;i<text.length();i++) { char c = text.charAt(i); scanedText += c; String t = scanedText; if(i<text.length()-1){ t += text.charAt(i+1); } TextBounds tb = style.font.getBounds(t); if(tb.width >= getWidth() - renderOffset ) { scanedText += '\n'; outputText += scanedText; scanedText = ""; } if(i==text.length() -1){ outputText += scanedText; } } return outputText; } public void append(String text) { // TODO Auto-generated method stub if (text == null) throw new IllegalArgumentException("text cannot be null."); if(text.length()==0) return; if(this.text.length()>0) { text = chopChopText(text); setText(this.text + "\n" + text); } else setText(text); } /** @return Never null, might be an empty string. */ public String getText () { return text; } /** Sets the selected text. */ public void setSelection (int selectionStart, int selectionEnd) { if (selectionStart < 0) throw new IllegalArgumentException("selectionStart must be >= 0"); if (selectionEnd < 0) throw new IllegalArgumentException("selectionEnd must be >= 0"); selectionStart = Math.min(text.length(), selectionStart); selectionEnd = Math.min(text.length(), selectionEnd); if (selectionEnd == selectionStart) { clearSelection(); return; } if (selectionEnd < selectionStart) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } hasSelection = true; this.selectionStart = selectionStart; cursor = selectionEnd; } public void selectAll () { setSelection(0, text.length()); } public void clearSelection () { hasSelection = false; } /** Sets the cursor position and clears any selection. */ public void setCursorPosition (int cursorPosition) { if (cursorPosition < 0) throw new IllegalArgumentException("cursorPosition must be >= 0"); clearSelection(); cursor = Math.min(cursorPosition, text.length()); } public int getCursorPosition () { return cursor; } /** Default is an instance of {@link DefaultOnscreenKeyboard}. */ public OnscreenKeyboard getOnscreenKeyboard () { return keyboard; } public void setOnscreenKeyboard (OnscreenKeyboard keyboard) { this.keyboard = keyboard; } public void setClipboard (Clipboard clipboard) { this.clipboard = clipboard; } public float getPrefWidth () { return 150; } public float getPrefHeight () { float prefHeight = textBounds.height; if (style.background != null) { prefHeight = Math.max(prefHeight + style.background.getBottomHeight() + style.background.getTopHeight(), style.background.getMinHeight()); } return prefHeight; } public void setRightAligned (boolean rightAligned) { this.rightAligned = rightAligned; } /** If true, the text in this text field will be shown as bullet characters. The font must have character 149 or this will have * no affect. */ public void setPasswordMode (boolean passwordMode) { this.passwordMode = passwordMode; updateDisplayText(); } public void setBlinkTime (float blinkTime) { this.blinkTime = blinkTime; } public void setDisabled (boolean disabled) { this.disabled = disabled; } public boolean isDisabled () { return disabled; } public boolean isPasswordMode () { return passwordMode; } public TextAreaFilter getTextAreaFilter () { return filter; } class KeyRepeatTask extends Task { int keycode; public void run () { inputListener.keyDown(null, keycode); } } /** Interface for listening to typed characters. * @author mzechner */ static public interface TextAreaListener { public void keyTyped (TextArea textField, char key); } /** Interface for filtering characters entered into the text field. * @author mzechner */ static public interface TextAreaFilter { /** @param textField * @param key * @return whether to accept the character */ public boolean acceptChar (TextArea textField, char key); static public class DigitsOnlyFilter implements TextAreaFilter { @Override public boolean acceptChar (TextArea textField, char key) { return Character.isDigit(key); } } } /** An interface for onscreen keyboards. Can invoke the default keyboard or render your own keyboard! * @author mzechner */ static public interface OnscreenKeyboard { public void show (boolean visible); } /** The default {@link OnscreenKeyboard} used by all {@link TextArea} instances. Just uses * {@link Input#setOnscreenKeyboardVisible(boolean)} as appropriate. Might overlap your actual rendering, so use with care! * @author mzechner */ static public class DefaultOnscreenKeyboard implements OnscreenKeyboard { @Override public void show (boolean visible) { Gdx.input.setOnscreenKeyboardVisible(visible); } } /** The style for a text field, see {@link TextArea}. * @author mzechner * @author Nathan Sweet */ static public class TextAreaStyle { public BitmapFont font; public Color fontColor, focusedFontColor, disabledFontColor; /** Optional. */ public Drawable background, focusedBackground, disabledBackground, cursor, selection; /** Optional. */ public BitmapFont messageFont; /** Optional. */ public Color messageFontColor; public TextAreaStyle () { } public TextAreaStyle (BitmapFont font, Color fontColor, Drawable cursor, Drawable selection, Drawable background) { this.background = background; this.cursor = cursor; this.font = font; this.fontColor = fontColor; this.selection = selection; } public TextAreaStyle (TextAreaStyle style) { this.messageFont = style.messageFont; if (style.messageFontColor != null) this.messageFontColor = new Color(style.messageFontColor); this.background = style.background; this.focusedBackground = style.focusedBackground; this.disabledBackground = style.disabledBackground; this.cursor = style.cursor; this.font = style.font; if (style.fontColor != null) this.fontColor = new Color(style.fontColor); if (style.focusedFontColor != null) this.focusedFontColor = new Color(style.focusedFontColor); if (style.disabledFontColor != null) this.disabledFontColor = new Color(style.disabledFontColor); this.selection = style.selection; } } }