import jexer.bits.CellAttributes;
import jexer.bits.GraphicsChars;
import jexer.bits.StringUtils;
+import jexer.event.TCommandEvent;
import jexer.event.TKeypressEvent;
import jexer.event.TMouseEvent;
+import static jexer.TCommand.*;
import static jexer.TKeypress.*;
/**
* TField implements an editable text field.
*/
-public class TField extends TWidget {
+public class TField extends TWidget implements EditMenuUser {
// ------------------------------------------------------------------------
// Variables --------------------------------------------------------------
if (keypress.equals(kbLeft)) {
if (position > 0) {
- if (position < text.length()) {
- screenPosition -= StringUtils.width(text.charAt(position));
- } else {
- screenPosition--;
- }
- position--;
+ screenPosition -= StringUtils.width(text.codePointBefore(position));
+ position -= Character.charCount(text.codePointBefore(position));
}
if (fixed == false) {
if ((screenPosition == windowStart) && (windowStart > 0)) {
- windowStart -= StringUtils.width(text.charAt(
+ windowStart -= StringUtils.width(text.codePointAt(
screenToTextPosition(windowStart)));
}
}
if (keypress.equals(kbRight)) {
if (position < text.length()) {
- screenPosition += StringUtils.width(text.charAt(position));
- position++;
+ int lastPosition = position;
+ screenPosition += StringUtils.width(text.codePointAt(position));
+ position += Character.charCount(text.codePointAt(position));
if (fixed == true) {
if (screenPosition == getWidth()) {
screenPosition--;
- position--;
+ position -= Character.charCount(text.codePointAt(lastPosition));
}
} else {
- if ((screenPosition - windowStart) >= getWidth()) {
- windowStart += StringUtils.width(text.charAt(
+ while ((screenPosition - windowStart +
+ StringUtils.width(text.codePointAt(text.length() - 1)))
+ > getWidth()
+ ) {
+ windowStart += StringUtils.width(text.codePointAt(
screenToTextPosition(windowStart)));
}
}
}
+ assert (position <= text.length());
return;
}
if (keypress.equals(kbBackspace) || keypress.equals(kbBackspaceDel)) {
if (position > 0) {
- position--;
+ position -= Character.charCount(text.codePointBefore(position));
text = text.substring(0, position)
+ text.substring(position + 1);
screenPosition = StringUtils.width(text.substring(0, position));
if ((screenPosition >= windowStart)
&& (windowStart > 0)
) {
- windowStart -= StringUtils.width(text.charAt(
+ windowStart -= StringUtils.width(text.codePointAt(
screenToTextPosition(windowStart)));
}
}
if (insertMode == false) {
// Replace character
text = text.substring(0, position)
- + keypress.getKey().getChar()
+ + codePointString(keypress.getKey().getChar())
+ text.substring(position + 1);
- screenPosition += StringUtils.width(text.charAt(position));
- position++;
+ screenPosition += StringUtils.width(text.codePointAt(position));
+ position += Character.charCount(keypress.getKey().getChar());
} else {
// Insert character
insertChar(keypress.getKey().getChar());
} else if ((fixed == true) && (insertMode == false)) {
// Overwrite the last character, maybe move position
text = text.substring(0, position)
- + keypress.getKey().getChar()
+ + codePointString(keypress.getKey().getChar())
+ text.substring(position + 1);
if (screenPosition < getWidth() - 1) {
- screenPosition += StringUtils.width(text.charAt(position));
- position++;
+ screenPosition += StringUtils.width(text.codePointAt(position));
+ position += Character.charCount(keypress.getKey().getChar());
}
} else if ((fixed == false) && (insertMode == false)) {
// Overwrite the last character, definitely move position
text = text.substring(0, position)
- + keypress.getKey().getChar()
+ + codePointString(keypress.getKey().getChar())
+ text.substring(position + 1);
- screenPosition += StringUtils.width(text.charAt(position));
- position++;
+ screenPosition += StringUtils.width(text.codePointAt(position));
+ position += Character.charCount(keypress.getKey().getChar());
} else {
if (position == text.length()) {
// Append this character
super.onKeypress(keypress);
}
+ /**
+ * Handle posted command events.
+ *
+ * @param command command event
+ */
+ @Override
+ public void onCommand(final TCommandEvent command) {
+ if (command.equals(cmCut)) {
+ // Copy text to clipboard, and then remove it.
+ getClipboard().copyText(text);
+ setText("");
+ return;
+ }
+
+ if (command.equals(cmCopy)) {
+ // Copy text to clipboard.
+ getClipboard().copyText(text);
+ return;
+ }
+
+ if (command.equals(cmPaste)) {
+ // Paste text from clipboard.
+ String newText = getClipboard().pasteText();
+ if (newText != null) {
+ setText(newText);
+ }
+ return;
+ }
+
+ if (command.equals(cmClear)) {
+ // Remove text.
+ setText("");
+ return;
+ }
+
+ }
+
// ------------------------------------------------------------------------
// TWidget ----------------------------------------------------------------
// ------------------------------------------------------------------------
+ /**
+ * Override TWidget's height: we can only set height at construction
+ * time.
+ *
+ * @param height new widget height (ignored)
+ */
+ @Override
+ public void setHeight(final int height) {
+ // Do nothing
+ }
+
/**
* Draw the text field.
*/
// TField -----------------------------------------------------------------
// ------------------------------------------------------------------------
+ /**
+ * Convert a char (codepoint) to a string.
+ *
+ * @param ch the char
+ * @return the string
+ */
+ private String codePointString(final int ch) {
+ StringBuilder sb = new StringBuilder(1);
+ sb.append(Character.toChars(ch));
+ assert (Character.charCount(ch) == sb.length());
+ return sb.toString();
+ }
+
/**
* Get field background character.
*
assert (text != null);
this.text = text;
position = 0;
+ screenPosition = 0;
windowStart = 0;
+ if ((fixed == true) && (this.text.length() > getWidth())) {
+ this.text = this.text.substring(0, getWidth());
+ }
}
/**
protected void dispatch(final boolean enter) {
if (enter) {
if (enterAction != null) {
- enterAction.DO();
+ enterAction.DO(this);
}
} else {
if (updateAction != null) {
- updateAction.DO();
+ updateAction.DO(this);
}
}
}
int n = 0;
for (int i = 0; i < text.length(); i++) {
- n += StringUtils.width(text.charAt(i));
+ n += StringUtils.width(text.codePointAt(i));
if (n >= screenPosition) {
return i + 1;
}
*/
protected void appendChar(final int ch) {
// Append the LAST character
- text += ch;
- position++;
+ text += codePointString(ch);
+ position += Character.charCount(ch);
screenPosition += StringUtils.width(ch);
assert (position == text.length());
if (fixed) {
if (screenPosition >= getWidth()) {
- position--;
+ position -= Character.charCount(ch);
screenPosition -= StringUtils.width(ch);
}
} else {
* @param ch char to append
*/
protected void insertChar(final int ch) {
- text = text.substring(0, position) + ((char) ch) + text.substring(position);
- position++;
+ text = text.substring(0, position) + codePointString(ch)
+ + text.substring(position);
+ position += Character.charCount(ch);
screenPosition += StringUtils.width(ch);
if ((screenPosition - windowStart) == getWidth()) {
assert (!fixed);
screenPosition = StringUtils.width(text);
if (fixed == true) {
if (screenPosition >= getWidth()) {
- position = text.length() - 1;
+ position -= Character.charCount(text.codePointBefore(position));
screenPosition = StringUtils.width(text) - 1;
}
} else {
public void setPosition(final int position) {
if ((position < 0) || (position >= text.length())) {
throw new IndexOutOfBoundsException("Max length is " +
- StringUtils.width(text) + ", requested position " + position);
+ text.length() + ", requested position " + position);
}
this.position = position;
normalizeWindowStart();
updateAction = action;
}
+ // ------------------------------------------------------------------------
+ // EditMenuUser -----------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Check if the cut menu item should be enabled.
+ *
+ * @return true if the cut menu item should be enabled
+ */
+ public boolean isEditMenuCut() {
+ return true;
+ }
+
+ /**
+ * Check if the copy menu item should be enabled.
+ *
+ * @return true if the copy menu item should be enabled
+ */
+ public boolean isEditMenuCopy() {
+ return true;
+ }
+
+ /**
+ * Check if the paste menu item should be enabled.
+ *
+ * @return true if the paste menu item should be enabled
+ */
+ public boolean isEditMenuPaste() {
+ return true;
+ }
+
+ /**
+ * Check if the clear menu item should be enabled.
+ *
+ * @return true if the clear menu item should be enabled
+ */
+ public boolean isEditMenuClear() {
+ return true;
+ }
+
}