Editable Textarea (work in progress)

I need an editable textarea for my game and so I set about adapting the nifty textfield to one.

There are a few things left to fix (some requiring a change in nifty text render code), but I thought the current state was good enough that others might have use for it, so I thought I’d share it here.

Note that to get wrapping to work correctly requires a fix I very recently submitted to nifty and which I don’t know when it’ll be included in the jme library. Note also that you need to change some paths if you want to use this (like controller path and package names). Thirdly, not that it currently uses the TextField interface, which is all well and good now, but probably will change later.



I’ll probably wrap it in a scroll panel later, so when you get to the bottom of the textarea, it scrolls automatically (right now it just goes on, though the text is clipped). Other bugs include no mouse drag to select (need some small changes in nifty for that) and no up/down movement (will probably fix this soon) - fixed.



Textarea control definition:

[xml]<?xml version=“1.0” encoding=“UTF-8”?>

<nifty-controls>

<controlDefinition style=“nifty-textfield” name=“textarea” controller=“com.limewoodGames.holicity.test.nifty.editTextArea.TextAreaControl” inputMapping=“de.lessvoid.nifty.controls.textfield.TextFieldInputMapping” passwordChar="$passwordChar" maxLength="$maxLength">

<panel style="#panel" focusable=“true”>

<interact onClick=“onClick()” onClickMouseMove=“onClickMouseMove()” />

<panel id="#field" style="#field" visibleToMouse=“true”>

<text id="#text" style="#text" text="$text" wrap=“true” valign=“top” textVAlign=“top” width=“100%” height=“100%” />

</panel>

<panel style="#cursor-panel">

<image id="#cursor" style="#cursor"/>

</panel>

</panel>

</controlDefinition>

</nifty-controls>[/xml]



TextAreaControl:

[java]package com.limewoodGames.holicity.test.nifty.editTextArea;



import java.util.Properties;



import de.lessvoid.nifty.Nifty;

import de.lessvoid.nifty.controls.AbstractController;

import de.lessvoid.nifty.controls.FocusHandler;

import de.lessvoid.nifty.controls.TextField;

import de.lessvoid.nifty.controls.TextFieldChangedEvent;

import de.lessvoid.nifty.controls.textfield.TextFieldView;

import de.lessvoid.nifty.effects.EffectEventId;

import de.lessvoid.nifty.elements.Element;

import de.lessvoid.nifty.elements.render.TextRenderer;

import de.lessvoid.nifty.elements.tools.FontHelper;

import de.lessvoid.nifty.input.NiftyInputEvent;

import de.lessvoid.nifty.screen.Screen;

import de.lessvoid.nifty.tools.SizeValue;

import de.lessvoid.xml.xpp3.Attributes;



/**

  • An editable text area control.
  • @author void
  • @author Joakim Lindskog

    /

    public class TextAreaControl extends AbstractController implements TextField, TextFieldView {

    private static final int CURSOR_Y = 0;

    private Nifty nifty;

    private Screen screen;

    private Element textElement;

    private Element fieldElement;

    private Element cursorElement;

    private TextAreaLogic textArea;

    private int firstVisibleCharacterIndex;

    private int lastVisibleCharacterIndex;

    private int fieldWidth;

    private int fromClickCursorPos;

    private int toClickCursorPos;

    private FocusHandler focusHandler;

    private Character passwordChar;



    public void bind(

    final Nifty niftyParam,

    final Screen screenParam,

    final Element newElement,

    final Properties properties,

    final Attributes controlDefinitionAttributes) {

    super.bind(newElement);



    this.nifty = niftyParam;

    this.screen = screenParam;

    this.fromClickCursorPos = -1;

    this.toClickCursorPos = -1;



    this.textArea = new TextAreaLogic(properties.getProperty(“text”, “”), nifty.getClipboard(), this);

    this.textArea.toFirstPosition();



    this.textElement = getElement().findElementByName("#text");

    this.fieldElement = getElement().findElementByName("#field");

    this.cursorElement = getElement().findElementByName("#cursor");



    passwordChar = null;

    if (properties.containsKey(“passwordChar”)) {

    passwordChar = properties.get(“passwordChar”).toString().charAt(0);

    }

    if (properties.containsKey(“maxLength”)) {

    setMaxLength(new Integer(properties.getProperty(“maxLength”)));

    }

    }



    @Override

    public void init(final Properties parameter, final Attributes controlDefinitionAttributes) {

    this.focusHandler = screen.getFocusHandler();



    this.textArea.initWithText(textElement.getRenderer(TextRenderer.class).getOriginalText());

    this.fieldWidth = this.fieldElement.getWidth() - this.cursorElement.getWidth();



    TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);

    this.firstVisibleCharacterIndex = 0;

    this.lastVisibleCharacterIndex = FontHelper.getVisibleCharactersFromStart(textRenderer.getFont(), this.textArea.getText(), fieldWidth, 1.0f);



    updateCursor();

    super.init(parameter, controlDefinitionAttributes);

    }



    public void onStartScreen() {

    }



    @Override

    public void layoutCallback() {

    this.fieldWidth = this.fieldElement.getWidth() - this.cursorElement.getWidth();

    }



    public void onClick(final int mouseX, final int mouseY) {

    //Find out what row is clicked

    TextRenderer renderer = textElement.getRenderer(TextRenderer.class);

    String text = renderer.getWrappedText();

    int row = (mouseY - fieldElement.getY()) / renderer.getFont().getHeight();

    if(row > text.split(“n”, -1).length-1)

    row = text.split(“n”, -1).length-1;

    String[] split = text.split(“n”, row+2);

    String visibleString = /editTextArea.getText()/split[row];//.substring(firstVisibleCharacterIndex, lastVisibleCharacterIndex);

    StringBuffer buf = new StringBuffer();

    for(int i=0; i<row; i++) {

    if(buf.length() == 0)

    buf.append(split+" ");

    else

    buf.append(‘n’+split);

    }

    int indexFromPixel = getCursorPosFromMouse(mouseX, visibleString)+buf.length();

    if (indexFromPixel != -1) {

    fromClickCursorPos = firstVisibleCharacterIndex + indexFromPixel;

    }

    textArea.resetSelection();

    textArea.setCursorPosition(fromClickCursorPos);

    updateCursor();

    }



    public void onClickMouseMove(final int mouseX, final int mouseY) {

    //TODO Fix NiftyRenderEngineImpl

    if(true) return;

    TextRenderer renderer = textElement.getRenderer(TextRenderer.class);

    String text = renderer.getWrappedText();

    int row = (mouseY - fieldElement.getY()) / renderer.getFont().getHeight();

    if(row > text.split(“n”, -1).length-1)

    row = text.split(“n”, -1).length-1;

    System.out.println("wrapped text::: "+text);

    System.out.println("row: “+row+” firstVisCharIdx: "+firstVisibleCharacterIndex);

    String[] split = text.split(“n”, row+2);

    System.out.println("text: “+split[row]+” split length: “+split.length);

    // String visibleString = textField.getText().substring(firstVisibleCharacterIndex, lastVisibleCharacterIndex);

    String visibleString = /editTextArea.getText()/split[row];//.substring(firstVisibleCharacterIndex, lastVisibleCharacterIndex);

    StringBuffer buf = new StringBuffer();

    for(int i=0; i<row; i++) {

    if(buf.length() == 0)

    buf.append(split+” ");

    else

    buf.append(‘n’+split);

    }



    // String visibleString = textArea.getText().substring(firstVisibleCharacterIndex, lastVisibleCharacterIndex);

    int indexFromPixel = getCursorPosFromMouse(mouseX, visibleString)+buf.length();

    if (indexFromPixel != -1) {

    toClickCursorPos = firstVisibleCharacterIndex + indexFromPixel;

    }



    System.out.println("fromClickCursorPos "+fromClickCursorPos);

    textArea.setCursorPosition(fromClickCursorPos);

    textArea.startSelecting();

    System.out.println("toClickCursorPos "+toClickCursorPos);

    textArea.setCursorPosition(toClickCursorPos);

    textArea.endSelecting();

    updateCursor();

    }



    private int getCursorPosFromMouse(final int mouseX, final String visibleString) {

    TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);

    return FontHelper.getCharacterIndexFromPixelPosition(

    textRenderer.getFont(), visibleString, (mouseX - fieldElement.getX()), 1.0f);

    }



    public boolean inputEvent(final NiftyInputEvent inputEvent) {

    if (inputEvent == NiftyInputEvent.MoveCursorLeft) {

    textArea.cursorLeft();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.MoveCursorRight) {

    textArea.cursorRight();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.MoveCursorUp) {

    textArea.cursorUp();

    updateCursor();

    } else if (inputEvent == NiftyInputEvent.MoveCursorDown) {

    textArea.cursorDown();

    updateCursor();

    } else if (inputEvent == NiftyInputEvent.Delete) {

    textArea.delete();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.Backspace) {

    textArea.backspace();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.MoveCursorToLastPosition) {

    textArea.toLastPosition();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.MoveCursorToFirstPosition) {

    textArea.toFirstPosition();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.SelectionStart) {

    textArea.startSelecting();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.SelectionEnd) {

    textArea.endSelecting();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.Cut) {

    textArea.cut(passwordChar);

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.Copy) {

    textArea.copy(passwordChar);

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.Paste) {

    textArea.put();

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.SelectAll) {

    if (textArea.getText().length() > 0) {

    textArea.setCursorPosition(0);

    textArea.startSelecting();

    textArea.setCursorPosition(textArea.getText().length());

    textArea.endSelecting();

    updateCursor();

    return true;

    }

    } else if (inputEvent == NiftyInputEvent.Character) {

    textArea.insert(inputEvent.getCharacter());

    updateCursor();

    return true;

    } else if (inputEvent == NiftyInputEvent.NextInputElement) {

    if (focusHandler != null) {

    focusHandler.getNext(fieldElement).setFocus();

    updateCursor();

    return true;

    }

    } else if (inputEvent == NiftyInputEvent.PrevInputElement) {

    textArea.endSelecting();

    if (focusHandler != null) {

    focusHandler.getPrev(fieldElement).setFocus();

    updateCursor();

    return true;

    }

    } else if (inputEvent == NiftyInputEvent.SubmitText) {

    textArea.insert(‘n’);

    }



    updateCursor();

    return false;

    }



    private void updateCursor() {

    TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);

    String text = textArea.getText();

    checkBounds(text, textRenderer);

    calcLastVisibleIndex(textRenderer);



    // update text

    if (isPassword(passwordChar)) {

    int numChar = text.length();

    char[] chars = new char[numChar];

    for (int i = 0; i < numChar; ++i) {

    chars = passwordChar;

    }

    text = new String(chars);

    }



    textRenderer.setText(text);

    textRenderer.setSelection(textArea.getSelectionStart(), textArea.getSelectionEnd());

    // Lay out element to get correctly wrapped text

    getElement().getParent().layoutElements();



    //Get the position of the cursor in the text

    int cursorPos = textArea.getCursorPosition();



    // outside, move window to fit cursorPos inside [first,last]

    //calcFirstVisibleIndex(cursorPos);

    //calcLastVisibleIndex(textRenderer);



    String substring2 = text.substring(0, firstVisibleCharacterIndex);

    int d = textRenderer.getFont().getWidth(substring2);

    textRenderer.setXoffsetHack(-d);



    // Get wrapped text

    String breakText = textRenderer.getWrappedText();

    // Get the current line

    int currentLine = breakText.substring(0, cursorPos > 0 ? cursorPos : 0).split(“n”, -1).length;



    int startIndex = breakText.lastIndexOf(‘n’)+1;

    if(cursorPos-startIndex<0) {

    // Going up to previous line

    startIndex = breakText.substring(0, cursorPos).lastIndexOf(‘n’)+1;

    }

    int textWidth = textRenderer.getFont().getWidth(breakText.substring(startIndex > -1 ? startIndex : 0,

    cursorPos > 0 ? cursorPos : 0));

    int cursorPixelPos = textWidth - d;



    cursorElement.setConstraintX(new SizeValue(cursorPixelPos + “px”));

    cursorElement.setConstraintY(new SizeValue((textRenderer.getFont().getHeight()
    (currentLine-1)) + CURSOR_Y + “px”));

    cursorElement.startEffect(EffectEventId.onActive, null);

    if (screen != null) {

    screen.layoutLayers();

    }

    }



    private boolean isPassword(final Character currentPasswordChar) {

    return currentPasswordChar != null;

    }



    private void calcFirstVisibleIndex(final int cursorPos) {

    if (cursorPos > lastVisibleCharacterIndex) {

    int cursorPosDelta = cursorPos - lastVisibleCharacterIndex;

    firstVisibleCharacterIndex += cursorPosDelta;

    } else if (cursorPos < firstVisibleCharacterIndex) {

    int cursorPosDelta = firstVisibleCharacterIndex - cursorPos;

    firstVisibleCharacterIndex -= cursorPosDelta;

    }

    }



    private void checkBounds(final String text, final TextRenderer textRenderer) {

    int textLen = text.length();

    if (firstVisibleCharacterIndex > textLen) {

    // reposition so that we show as much text as possible

    lastVisibleCharacterIndex = textLen;

    firstVisibleCharacterIndex =

    FontHelper.getVisibleCharactersFromEnd(textRenderer.getFont(), text, fieldWidth, 1.0f);

    }

    }



    private void calcLastVisibleIndex(final TextRenderer textRenderer) {

    String currentText = this.textArea.getText();

    if (firstVisibleCharacterIndex < currentText.length()) {

    String textToCheck = currentText.substring(firstVisibleCharacterIndex);

    int lengthFitting =

    FontHelper.getVisibleCharactersFromStart(textRenderer.getFont(), textToCheck, fieldWidth, 1.0f);

    lastVisibleCharacterIndex = lengthFitting + firstVisibleCharacterIndex;

    } else {

    lastVisibleCharacterIndex = firstVisibleCharacterIndex;

    }

    }



    public void onFocus(final boolean getFocus) {

    if (cursorElement != null) {

    super.onFocus(getFocus);

    if (getFocus) {

    cursorElement.startEffect(EffectEventId.onCustom);

    } else {

    cursorElement.stopEffect(EffectEventId.onCustom);

    }

    updateCursor();

    }

    }



    public String getText() {

    return textArea.getText();

    }



    public void setText(final String newText) {

    textArea.initWithText(nifty.specialValuesReplace(newText));

    updateCursor();

    }



    public void setMaxLength(final int maxLength) {

    textArea.setMaxLength(maxLength);

    updateCursor();

    }



    public void setCursorPosition(final int position) {

    textArea.setCursorPosition(position);

    updateCursor();

    }



    @Override

    public void textChangeEvent(final String newText) {

    nifty.publishEvent(getElement().getId(), new TextFieldChangedEvent(this, newText));

    }



    @Override

    public void enablePasswordChar(final char passwordChar) {

    this.passwordChar = passwordChar;

    updateCursor();

    }



    @Override

    public void disablePasswordChar() {

    this.passwordChar = null;

    updateCursor();

    }



    @Override

    public boolean isPasswordCharEnabled() {

    return passwordChar != null;

    }

    }[/java]



    TextAreaLogic:

    [java]package com.limewoodGames.holicity.test.nifty.editTextArea;



    import de.lessvoid.nifty.Clipboard;

    import de.lessvoid.nifty.controls.textfield.TextFieldView;



    /**
  • TextArea logic.
  • @author void
  • @author Joakim Lindskog

    */

    public class TextAreaLogic {



    /**
  • the text.

    */

    private StringBuffer text;



    /**
  • the current cursor position in the string.

    */

    private int cursorPosition;



    /**
  • Index of first selected character.

    */

    private int selectionStart = -1;



    /**
  • Index of last selected character.

    */

    private int selectionEnd = -1;



    /**
  • currently selecting stuff.

    */

    private boolean selecting;



    /**
  • cursor position we start the selection mode.

    */

    private int selectionStartIndex;



    /**
  • clipboard.

    */

    private Clipboard clipboard;



    private int maxLength = -1;



    private TextFieldView view;



    /**
  • Create TextField with clipboard support.
  • @param newText init text
  • @param newClipboard clipboard

    */

    public TextAreaLogic(final String newText, final Clipboard newClipboard, final TextFieldView textFieldView) {

    this.view = textFieldView;

    initText(newText);

    clipboard = newClipboard;

    maxLength = -1;

    }



    /**
  • init instance wit the given text.
  • @param newText new text

    */

    public void initWithText(final String newText) {

    changeText(newText);



    if (newText != null && newText.length() > 0) {

    view.textChangeEvent(newText);

    }

    }



    private void initText(final String newText) {

    this.text = new StringBuffer();

    if (newText != null) {

    this.text.append(newText);

    }

    this.cursorPosition = 0;

    this.selectionStart = -1;

    this.selectionEnd = -1;

    this.selecting = false;

    this.selectionStartIndex = -1;

    }



    private void changeText(final String newText) {

    this.text = new StringBuffer();

    if (newText != null) {

    this.text.append(newText);

    }

    // only reset the cursorposition if the old one is not valid anymore

    if (this.cursorPosition > this.text.length()) {

    this.cursorPosition = 0;

    }

    this.selectionStart = -1;

    this.selectionEnd = -1;

    this.selecting = false;

    this.selectionStartIndex = -1;

    }



    /**
  • Return the current text.
  • @return the current text

    */

    public String getText() {

    return text.toString();

    }



    /**
  • Get cursor position.
  • @return current cursor position

    */

    public int getCursorPosition() {

    return cursorPosition;

    }



    /**
  • Move cursor left.

    */

    public void cursorLeft() {

    cursorPosition–;

    if (cursorPosition < 0) {

    cursorPosition = 0;

    }



    if (selecting) {

    selectionFromCursorPosition();

    } else {

    resetSelection();

    }

    }



    /**
  • Move cursor right.

    */

    public void cursorRight() {

    cursorPosition++;

    if (cursorPosition > text.length()) {

    cursorPosition = text.length();

    }



    if (selecting) {

    selectionFromCursorPosition();

    } else {

    resetSelection();

    }

    }



    /**
  • Move cursor up.

    */

    public void cursorUp() {

    // Check if there is a previous row

    String q = text.substring(0,cursorPosition);

    if(q.indexOf(‘n’) == -1) {

    cursorPosition = 0;

    }

    else {

    int prev = q.lastIndexOf(‘n’)+1;

    int prev2 = text.substring(0, prev-1).lastIndexOf(‘n’)+1;



    int offset = cursorPosition-prev;

    if(offset > prev-1-prev2) cursorPosition = prev-1;

    else cursorPosition = prev2+offset;

    }



    if (selecting) {

    selectionFromCursorPosition();

    } else {

    resetSelection();

    }

    }



    /**
  • Move cursor down.

    */

    public void cursorDown() {

    // Check if there is a next row

    String q = text.substring(cursorPosition);

    if(q.indexOf(‘n’) == -1) {

    cursorPosition = text.length();

    }

    else {

    int next = cursorPosition+q.indexOf(‘n’)+1;



    int rowEnd = next+text.substring(next).indexOf(‘n’);

    if(rowEnd < next) rowEnd = text.length();



    int offset = cursorPosition-(text.substring(0, cursorPosition).lastIndexOf(‘n’)+1);

    if(offset > rowEnd-next) cursorPosition = rowEnd;

    else cursorPosition = next+offset;

    }



    if (selecting) {

    selectionFromCursorPosition();

    } else {

    resetSelection();

    }

    }



    /

    *

    */

    private void selectionFromCursorPosition() {

    if (cursorPosition > selectionStartIndex) {

    selectionStart = selectionStartIndex;

    selectionEnd = cursorPosition;

    } else if (cursorPosition == selectionStartIndex) {

    resetSelection();

    } else {

    selectionStart = cursorPosition;

    selectionEnd = selectionStartIndex;

    }

    }



    /

  • Delete the character at the cursor position.

    */

    public void delete() {

    String old = text.toString();

    if (hasSelection()) {

    text.delete(selectionStart, selectionEnd);

    cursorPosition = selectionStart;

    resetSelection();

    } else {

    text.delete(cursorPosition, cursorPosition + 1);

    }

    notifyTextChange(old);

    }



    /**
  • checks if we currently have a selection.
  • @return true or false

    */

    public boolean hasSelection() {

    return (selectionStart != -1 && selectionEnd != -1);

    }



    /**
  • Position cursor to first character.

    */

    public void toFirstPosition() {

    // cursorPosition = 0;

    cursorPosition = text.substring(0, cursorPosition).lastIndexOf("n")+1;

    if (selecting) {

    selectionFromCursorPosition();

    } else if (hasSelection()) {

    resetSelection();

    }

    }



    /**
  • Position cursor to last character.

    */

    public void toLastPosition() {

    // cursorPosition = text.length();

    int curPos = text.substring(cursorPosition).indexOf("n");

    cursorPosition = curPos > -1 ? curPos+cursorPosition : text.length();

    if (selecting) {

    selectionFromCursorPosition();

    } else if (hasSelection()) {

    resetSelection();

    }

    }



    /**
  • Backspace.

    */

    public void backspace() {

    String old = text.toString();

    if (hasSelection()) {

    text.delete(selectionStart, selectionEnd);

    cursorPosition = selectionStart;

    resetSelection();

    } else {

    if (cursorPosition > 0) {

    // delete character left of cursor

    text.delete(cursorPosition - 1, cursorPosition);

    cursorPosition–;

    }

    }

    notifyTextChange(old);

    }



    /**
  • reset the selection.

    */

    public void resetSelection() {

    selectionStart = -1;

    selectionEnd = -1;

    selecting = false;

    }



    /**
  • Insert character at cursor position.
  • @param c

    */

    public void insert(final char c) {

    String old = text.toString();

    if (hasSelection()) {

    text.delete(selectionStart, selectionEnd);

    cursorPosition = selectionStart;

    resetSelection();

    }

    if (maxLength == -1 || text.length() < maxLength) {

    text.insert(cursorPosition, c);

    cursorPosition++;

    }

    notifyTextChange(old);

    }



    /**
  • Set new cursor position.
  • @param newIndex index.

    */

    public void setCursorPosition(final int newIndex) {

    if (newIndex < 0) {

    cursorPosition = 0;

    } else if (newIndex > text.length()) {

    cursorPosition = text.length();

    } else {

    cursorPosition = newIndex;

    }



    if (selecting) {

    selectionFromCursorPosition();

    }

    }



    /**
  • Get selection start.
  • @return selection start index

    */

    public int getSelectionStart() {

    return selectionStart;

    }



    /**
  • Get selection end.
  • @return selection end index

    */

    public int getSelectionEnd() {

    return selectionEnd;

    }



    /**
  • start selecting.

    */

    public void startSelecting() {

    selecting = true;

    selectionStartIndex = cursorPosition;

    }



    /**
  • end selecting.

    */

    public void endSelecting() {

    selecting = false;

    }



    /**
  • Return the selected text or null when there is no selection.
  • @return selected text or null

    */

    public String getSelectedText() {

    if (!hasSelection()) {

    return null;

    }

    return text.substring(selectionStart, selectionEnd);

    }



    /**
  • Cut the selected text into the clipboard.
  • @param passwordChar password character might be null

    */

    public void cut(final Character passwordChar) {

    String selectedText = getSelectedText();

    if (selectedText == null) {

    return;

    }

    clipboard.put(modifyWithPasswordChar(selectedText, passwordChar));

    delete();

    }



    /**
  • Copy currently selected text to clipboard.
  • @param passwordChar password character might be null

    */

    public void copy(final Character passwordChar) {

    String selectedText = modifyWithPasswordChar(getSelectedText(), passwordChar);

    if (selectedText != null) {

    clipboard.put(selectedText);

    }

    }



    String modifyWithPasswordChar(final String selectedText, final Character passwordChar) {

    if (passwordChar == null) {

    return selectedText;

    }

    if (selectedText == null) {

    return null;

    }

    String result = selectedText;

    return result.replaceAll(".", new String(new char[]{passwordChar}));

    }



    /**
  • Put data from clipboard into textfield.

    /

    public void put() {

    String clipboardText = clipboard.get();

    if (clipboardText != null) {

    for (int i = 0; i < clipboardText.length(); i++) {

    insert(clipboardText.charAt(i));

    }

    }

    }



    public void setMaxLength(final int maxLen) {

    maxLength = maxLen;



    if (maxLength != -1) {

    if (text.length() > maxLen) {

    setCursorPosition(maxLen);

    startSelecting();

    setCursorPosition(text.length());

    delete();

    }

    }

    }



    private void notifyTextChange(final String old) {

    String current = text.toString();

    if (old.equals(current)) {

    return;

    }

    view.textChangeEvent(current);

    }

    }[/java]



    Finally, a test:

    [xml]<?xml version="1.0" encoding="UTF-8"?>

    <nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty.xsd-1.3">



    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <!-- load default styles and controls -->

    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <useStyles filename="nifty-default-styles.xml" />

    <useControls filename="nifty-default-controls.xml" />

    <useControls filename="com/limewoodGames/holicity/test/nifty/editTextArea/textarea.xml" />



    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <!-- start screen -->

    <!-- +++++++++++++++++++++++++++++++++++++++ -->

    <screen id="start">

    <layer id="layer" childLayout="center" width="100%" height="100%">

    <panel childLayout="vertical" width="400" height="400" padding="20px">

    <control name="textarea" width="80%" height="80%" />

    <panel width="100%" height="5px" />

    <control name="textfield" />

    </panel>

    </layer>

    </screen>

    </nifty>[/xml]



    [java]/

  • Created on 12.02.2005

    *

    */

    package com.limewoodGames.holicity.test.nifty.editTextArea;



    import java.util.logging.ConsoleHandler;

    import java.util.logging.Handler;

    import java.util.logging.Level;

    import java.util.logging.Logger;



    import com.jme3.app.SimpleApplication;

    import com.jme3.niftygui.NiftyJmeDisplay;

    import com.jme3.system.AppSettings;



    import de.lessvoid.nifty.Nifty;



    /**
  • A textarea test with Nifty and JME3
  • @author Joakim Lindskog

    *

    */

    public class TextAreaTest extends SimpleApplication {

    public static void main(final String[] args) throws Exception {

    Logger root = Logger.getLogger("");

    Handler[] handlers = root.getHandlers();

    for (int i = 0; i < handlers.length; i++) {

    if (handlers instanceof ConsoleHandler) {

    ((ConsoleHandler) handlers).setLevel(Level.WARNING);

    }

    }



    TextAreaTest app = new TextAreaTest();

    AppSettings settings = new AppSettings(true);

    settings.setTitle("Nifty textarea test for JME3");

    settings.setResolution(800, 600);

    app.setSettings(settings);

    app.setPauseOnLostFocus(false);

    app.setShowSettings(false);

    app.start();

    }



    @Override

    public void simpleInitApp() {

    flyCam.setEnabled(false);



    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(

    assetManager,

    inputManager,

    audioRenderer,

    guiViewPort);



    Nifty nifty = niftyDisplay.getNifty();

    nifty.fromXml("com/limewoodGames/holicity/test/nifty/editTextArea/textareaTest.xml", "start");



    guiViewPort.addProcessor(niftyDisplay);



    mouseInput.setCursorVisible(true);

    }



    public void renderLineExample(final String text, int selectionStart, int selectionEnd) {

    if(selectionStart > text.length()) {

    selectionStart = text.length();

    }

    if(selectionEnd > text.length()) {

    selectionEnd = text.length();

    }

    String unselectedString1 = text.substring(0, selectionStart);

    String selectedString = text.substring(selectionStart, selectionEnd);

    String unselectedString2 = text.substring(selectionEnd, text.length());

    }

    }[/java]



    PS. Perhaps this is better in User Code & Projects?



    Update: Added support for up/down movement in the text.
1 Like