Re-implement GuiTextField without depending on the Minecraft Text Field

This commit is contained in:
johni0702
2015-11-27 15:22:06 +01:00
parent 859e9bb937
commit 6ee3ef229a
6 changed files with 648 additions and 139 deletions

View File

@@ -8,6 +8,7 @@ import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.element.GuiPasswordField;
import de.johni0702.minecraft.gui.element.GuiTextField;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.utils.Consumer;
import eu.crushedpixel.replaymod.gui.GuiConstants;
public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
@@ -72,9 +73,9 @@ public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
new GuiRegister(apiClient, GuiLoginPrompt.this).display();
}
});
Runnable contentValidation = new Runnable() {
Consumer<String> contentValidation = new Consumer<String>() {
@Override
public void run() {
public void consume(String obj) {
loginButton.setEnabled(!username.getText().isEmpty() && !password.getText().isEmpty());
}
};

View File

@@ -9,6 +9,7 @@ import de.johni0702.minecraft.gui.element.*;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.Consumers;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.utils.EmailAddressUtils;
import eu.crushedpixel.replaymod.utils.RegexUtils;
@@ -137,7 +138,7 @@ public class GuiRegister extends AbstractGuiScreen<GuiRegister> {
}
}
};
inputs.forEach(IGuiTextField.class).onTextChanged(contentValidation);
inputs.forEach(IGuiTextField.class).onTextChanged(Consumers.from(contentValidation));
cancelButton.onClick(new Runnable() {
@Override

View File

@@ -165,9 +165,9 @@ public class GuiReplayViewer extends GuiScreen {
popup.getYesButton().onClick();
}
}
}).onTextChanged(new Runnable() {
}).onTextChanged(new Consumer<String>() {
@Override
public void run() {
public void consume(String obj) {
popup.getYesButton().setEnabled(!nameField.getText().isEmpty());
}
});

View File

@@ -22,6 +22,7 @@
package de.johni0702.minecraft.gui.element;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
@@ -30,84 +31,401 @@ import de.johni0702.minecraft.gui.function.Clickable;
import de.johni0702.minecraft.gui.function.Focusable;
import de.johni0702.minecraft.gui.function.Tickable;
import de.johni0702.minecraft.gui.function.Typeable;
import de.johni0702.minecraft.gui.utils.Consumer;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import lombok.NonNull;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ChatAllowedCharacters;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableColor;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.*;
import static net.minecraft.client.renderer.GlStateManager.*;
import static net.minecraft.client.renderer.GlStateManager.disableColorLogic;
import static net.minecraft.client.renderer.GlStateManager.enableTexture2D;
import static net.minecraft.util.MathHelper.clamp_int;
public abstract class AbstractGuiTextField<T extends AbstractGuiTextField<T>>
extends AbstractGuiElement<T> implements Clickable, Tickable, Typeable, IGuiTextField<T> {
private final net.minecraft.client.gui.GuiTextField wrapped;
private Runnable textChanged;
private Runnable onEnter;
private static final ReadableColor BORDER_COLOR = new Color(160, 160, 160);
private static final ReadableColor CURSOR_COLOR = new Color(240, 240, 240);
private static final int BORDER = 4;
// Focus
@Getter
private boolean focused;
@Getter
private Focusable next, previous;
// Content
@Getter
private int maxLength = 32;
@Getter
@NonNull
private String text = "";
private int cursorPos;
private int selectionPos;
@Getter
private String hint;
@Getter
private ReadableColor textColor;
// Rendering
private int currentOffset;
private int blinkCursorTick;
public ReadableColor textColorEnabled = new Color(224, 224, 224);
public ReadableColor textColorDisabled = new Color(112, 112, 112);
private ReadableDimension size = new Dimension(0, 0); // Size of last render
private Consumer<String> textChanged;
private Runnable onEnter;
public AbstractGuiTextField() {
this.wrapped = new net.minecraft.client.gui.GuiTextField(0, Minecraft.getMinecraft().fontRendererObj, 0, 0, 0, 0);
}
public AbstractGuiTextField(GuiContainer container) {
super(container);
this.wrapped = new net.minecraft.client.gui.GuiTextField(0, Minecraft.getMinecraft().fontRendererObj, 0, 0, 0, 0);
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
ReadablePoint position = renderer.getOpenGlOffset();
wrapped.xPosition = position.getX() + 1;
wrapped.yPosition = position.getY() + 1;
wrapped.width = size.getWidth() - 2;
wrapped.height = size.getHeight() - 2;
if (wrapped.text.isEmpty() && !isFocused() && !Strings.isNullOrEmpty(hint)) {
wrapped.setEnabled(false);
wrapped.setDisabledTextColour(0xff404040);
wrapped.text = hint;
wrapped.drawTextBox();
wrapped.text = "";
wrapped.setDisabledTextColour(0xff707070);
wrapped.setEnabled(isEnabled());
public T setText(String text) {
if (text.length() > maxLength) {
this.text = text.substring(0, maxLength);
} else {
wrapped.drawTextBox();
this.text = text;
}
selectionPos = cursorPos = text.length();
return getThis();
}
@Override
public T setI18nText(@NonNull String text, @NonNull Object... args) {
return setText(I18n.format(text, args));
}
@Override
public T setMaxLength(int maxLength) {
Preconditions.checkArgument(maxLength >= 0, "maxLength must not be negative");
this.maxLength = maxLength;
if (text.length() > maxLength) {
setText(text);
}
return getThis();
}
@Override
public String deleteText(int from, int to) {
Preconditions.checkArgument(from <= to, "from must not be greater than to");
Preconditions.checkArgument(from >= 0, "from must be greater than zero");
Preconditions.checkArgument(to < text.length(), "to must be less than test.length()");
String deleted = text.substring(from, to + 1);
text = text.substring(0, from) + text.substring(to + 1);
return deleted;
}
@Override
public int getSelectionFrom() {
return cursorPos > selectionPos ? selectionPos : cursorPos;
}
@Override
public int getSelectionTo() {
return cursorPos > selectionPos ? cursorPos : selectionPos;
}
@Override
public String getSelectedText() {
return text.substring(getSelectionFrom(), getSelectionTo());
}
@Override
public String deleteSelectedText() {
if (cursorPos == selectionPos) {
return ""; // Nothing selected
}
int from = getSelectionFrom();
String deleted = deleteText(from, getSelectionTo() - 1);
cursorPos = selectionPos = from;
updateCurrentOffset();
return deleted;
}
/**
* Update current text offset to make sure the cursor is always visible.
*/
private void updateCurrentOffset() {
currentOffset = Math.min(currentOffset, cursorPos);
String line = text.substring(currentOffset, cursorPos);
FontRenderer fontRenderer = getMinecraft().fontRendererObj;
int currentWidth = fontRenderer.getStringWidth(line);
if (currentWidth > size.getWidth() - 2*BORDER) {
currentOffset = cursorPos - fontRenderer.trimStringToWidth(line, size.getWidth() - 2*BORDER, true).length();
}
}
@Override
public ReadableDimension calcMinSize() {
FontRenderer fontRenderer = getMinecraft().fontRendererObj;
return new Dimension(0, fontRenderer.FONT_HEIGHT);
public T writeText(String append) {
for (char c : append.toCharArray()) {
writeChar(c);
}
return getThis();
}
@Override
public T writeChar(char c) {
if (!ChatAllowedCharacters.isAllowedCharacter(c)) {
return getThis();
}
deleteSelectedText();
if (text.length() >= maxLength) {
return getThis();
}
text = text.substring(0, cursorPos) + c + text.substring(cursorPos);
selectionPos = ++cursorPos;
updateCurrentOffset();
return getThis();
}
@Override
public T deleteNextChar() {
if (cursorPos < text.length()) {
text = text.substring(0, cursorPos) + text.substring(cursorPos + 1);
}
selectionPos = cursorPos;
return getThis();
}
/**
* Return the amount of characters to the next word (excluding).
* If this is the last word in the line, return the amount of characters remaining to till the end.
* Everything except the Space character is considered part of a word.
* @return Length in characters
*/
protected int getNextWordLength() {
int length = 0;
boolean inWord = true;
for (int i = cursorPos; i < text.length(); i++) {
if (inWord) {
if (text.charAt(i) == ' ') {
inWord = false;
}
} else {
if (text.charAt(i) != ' ') {
return length;
}
}
length++;
}
return length;
}
@Override
public String deleteNextWord() {
int worldLength = getNextWordLength();
if (worldLength > 0) {
return deleteText(cursorPos, cursorPos + worldLength);
}
return "";
}
@Override
public T deletePreviousChar() {
if (cursorPos > 0) {
text = text.substring(0, cursorPos - 1) + text.substring(cursorPos);
selectionPos = --cursorPos;
updateCurrentOffset();
}
return getThis();
}
/**
* Return the amount of characters to the previous word (including).
* If this is the first word in the line, return the amount of characters till the start.
* Everything except the Space character is considered part of a word.
* @return Length in characters
*/
protected int getPreviousWordLength() {
int length = 0;
boolean inWord = false;
for (int i = cursorPos - 1; i >= 0; i--) {
if (inWord) {
if (text.charAt(i) == ' ') {
return length;
}
} else {
if (text.charAt(i) != ' ') {
inWord = true;
}
}
length++;
}
return length;
}
@Override
public String deletePreviousWord() {
int worldLength = getPreviousWordLength();
String deleted = "";
if (worldLength > 0) {
deleted = deleteText(cursorPos - worldLength, cursorPos);
selectionPos = cursorPos -= worldLength;
updateCurrentOffset();
}
return deleted;
}
@Override
public T setCursorPosition(int pos) {
Preconditions.checkArgument(pos >= 0 && pos <= text.length());
selectionPos = cursorPos = pos;
updateCurrentOffset();
return getThis();
}
/**
* Inverts all colors on the screen.
* @param guiRenderer The GUI Renderer
* @param right Right border of the inverted rectangle
* @param bottom Bottom border of the inverted rectangle
* @param left Left border of the inverted rectangle
* @param top Top border of the inverted rectangle
*/
private void invertColors(GuiRenderer guiRenderer, int right, int bottom, int left, int top) {
int x = guiRenderer.getOpenGlOffset().getX();
int y = guiRenderer.getOpenGlOffset().getY();
right+=x;
left+=x;
bottom+=y;
top+=y;
color(0, 0, 255, 255);
disableTexture2D();
enableColorLogic();
colorLogicOp(GL11.GL_OR_REVERSE);
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer renderer = tessellator.getWorldRenderer();
renderer.startDrawingQuads();
renderer.addVertex(right, top, 0);
renderer.addVertex(left, top, 0);
renderer.addVertex(left, bottom, 0);
renderer.addVertex(right, bottom, 0);
tessellator.draw();
disableColorLogic();
enableTexture2D();
}
@Override
protected ReadableDimension calcMinSize() {
return new Dimension(0, 0);
}
@Override
public boolean mouseClick(ReadablePoint position, int button) {
wrapped.mouseClicked(position.getX(), position.getY(), button);
return false;
if (getContainer() != null) {
getContainer().convertFor(this, (Point) (position = new Point(position)));
}
boolean hovering = isMouseHovering(position);
if (hovering && isFocused() && button == 0) {
int mouseX = position.getX() - BORDER;
FontRenderer fontRenderer = getMinecraft().fontRendererObj;
String text = this.text.substring(currentOffset);
int textX = fontRenderer.trimStringToWidth(text, mouseX).length() + currentOffset;
setCursorPosition(textX);
}
setFocused(hovering);
return hovering;
}
protected boolean isMouseHovering(ReadablePoint pos) {
return pos.getX() > 0 && pos.getY() > 0
&& pos.getX() < size.getWidth() && pos.getY() < size.getHeight();
}
@Override
public T setFocused(boolean isFocused) {
if (isFocused && !this.focused) {
this.blinkCursorTick = 0; // Restart blinking to indicate successful focus
}
this.focused = isFocused;
return getThis();
}
@Override
public T setNext(Focusable next) {
this.next = next;
return getThis();
}
@Override
public T setPrevious(Focusable previous) {
this.previous = previous;
return getThis();
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
this.size = size;
int width = size.getWidth(), height = size.getHeight();
FontRenderer fontRenderer = getMinecraft().fontRendererObj;
int posY = height / 2 - fontRenderer.FONT_HEIGHT / 2;
// Draw black rect once pixel smaller than gray rect
renderer.drawRect(0, 0, width, height, BORDER_COLOR);
renderer.drawRect(1, 1, width - 2, height - 2, ReadableColor.BLACK);
if (text.isEmpty() && !isFocused() && !Strings.isNullOrEmpty(hint)) {
// Draw hint
String text = fontRenderer.trimStringToWidth(hint, width - 2*BORDER);
renderer.drawString(BORDER, posY, textColorDisabled, text);
} else {
// Draw text
String renderText = text.substring(currentOffset);
renderText = fontRenderer.trimStringToWidth(renderText, width - 2*BORDER);
ReadableColor color = isEnabled() ? textColorEnabled : textColorDisabled;
int lineEnd = renderer.drawString(BORDER, height / 2 - fontRenderer.FONT_HEIGHT / 2, color, renderText);
// Draw selection
int from = getSelectionFrom();
int to = getSelectionTo();
String leftStr = text.substring(0, clamp_int(from - currentOffset, 0, text.length()));
String rightStr = text.substring(clamp_int(to - currentOffset, 0, text.length()));
int left = BORDER + fontRenderer.getStringWidth(leftStr);
int right = lineEnd - fontRenderer.getStringWidth(rightStr) - 1;
invertColors(renderer, right, height - 2, left, 2);
// Draw cursor
if (blinkCursorTick / 6 % 2 == 0 && focused) {
String beforeCursor = text.substring(0, cursorPos - currentOffset);
int posX = BORDER + fontRenderer.getStringWidth(beforeCursor);
if (cursorPos == text.length()) {
renderer.drawString(posX, posY, CURSOR_COLOR, "_", true);
} else {
renderer.drawRect(posX, posY - 1, 1, 1 + fontRenderer.FONT_HEIGHT, CURSOR_COLOR);
}
}
}
}
@Override
public boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown) {
if (!isFocused()) {
if (!this.focused) {
return false;
}
if (keyCode == Keyboard.KEY_RETURN) {
onEnter();
return true;
}
if (keyCode == Keyboard.KEY_TAB) {
Focusable other = shiftDown ? previous : next;
if (other != null) {
@@ -117,106 +435,131 @@ public abstract class AbstractGuiTextField<T extends AbstractGuiTextField<T>>
return true;
}
String before = wrapped.getText();
wrapped.textboxKeyTyped(keyChar, keyCode);
String after = wrapped.getText();
if (!before.equals(after)) {
if (textChanged != null) {
textChanged.run();
if (keyCode == Keyboard.KEY_RETURN) {
onEnter();
return true;
}
String textBefore = text;
try {
if (GuiScreen.isCtrlKeyDown()) {
switch (keyCode) {
case Keyboard.KEY_A: // Select all
cursorPos = 0;
selectionPos = text.length();
updateCurrentOffset();
return true;
case Keyboard.KEY_C: // Copy
GuiScreen.setClipboardString(getSelectedText());
return true;
case Keyboard.KEY_V: // Paste
if (isEnabled()) {
writeText(GuiScreen.getClipboardString());
}
return true;
case Keyboard.KEY_X: // Cut
if (isEnabled()) {
GuiScreen.setClipboardString(deleteSelectedText());
}
return true;
}
}
boolean words = GuiScreen.isCtrlKeyDown();
boolean select = GuiScreen.isShiftKeyDown();
switch (keyCode) {
case Keyboard.KEY_HOME:
cursorPos = 0;
break;
case Keyboard.KEY_END:
cursorPos = text.length();
break;
case Keyboard.KEY_LEFT:
if (cursorPos != 0) {
if (words) {
cursorPos -= getPreviousWordLength();
} else {
cursorPos--;
}
}
break;
case Keyboard.KEY_RIGHT:
if (cursorPos != text.length()) {
if (words) {
cursorPos += getNextWordLength();
} else {
cursorPos++;
}
}
break;
case Keyboard.KEY_BACK:
if (isEnabled()) {
if (getSelectedText().length() > 0) {
deleteSelectedText();
} else if (words) {
deletePreviousWord();
} else {
deletePreviousChar();
}
}
return true;
case Keyboard.KEY_DELETE:
if (isEnabled()) {
if (getSelectedText().length() > 0) {
deleteSelectedText();
} else if (words) {
deleteNextWord();
} else {
deleteNextChar();
}
}
return true;
default:
if (isEnabled()) {
if (keyChar == '\r') {
keyChar = '\n';
}
writeChar(keyChar);
}
return true;
}
updateCurrentOffset();
if (!select) {
selectionPos = cursorPos;
}
return true;
} finally {
if (!textBefore.equals(text)) {
onTextChanged(textBefore);
}
}
return true;
}
@Override
public T setText(String text) {
if (text.length() > wrapped.getMaxStringLength()) {
wrapped.text = text.substring(0, wrapped.getMaxStringLength());
} else {
wrapped.text = text;
}
return getThis();
}
@Override
public T setI18nText(String text, Object... args) {
return setText(I18n.format(text, args));
}
@Override
public String getText() {
return wrapped.text;
}
@Override
public boolean isFocused() {
return wrapped.isFocused();
}
@Override
public T setFocused(boolean focused) {
wrapped.setFocused(focused);
return getThis();
}
@Override
public Focusable getNext() {
return next;
}
@Override
public T setNext(Focusable next) {
if (this.next == next) return getThis();
if (this.next != null) {
this.next.setPrevious(null);
}
this.next = next;
if (this.next != null) {
this.next.setPrevious(this);
}
return getThis();
}
@Override
public Focusable getPrevious() {
return previous;
}
@Override
public T setPrevious(Focusable previous) {
if (this.previous == previous) return getThis();
if (this.previous != null) {
this.previous.setNext(null);
}
this.previous = previous;
if (this.previous != null) {
this.previous.setNext(this);
}
return getThis();
}
@Override
public int getMaxLength() {
return wrapped.getMaxStringLength();
}
@Override
public T setMaxLength(int maxLength) {
wrapped.setMaxStringLength(maxLength);
return getThis();
}
@Override
public void tick() {
wrapped.updateCursorCounter();
blinkCursorTick++;
}
/**
* Called when the user presses the Enter/Return key while this text field is focused.
*/
protected void onEnter() {
if (onEnter != null) {
onEnter.run();
}
}
/**
* Called when the text has changed due to user input.
*/
protected void onTextChanged(String from) {
if (textChanged != null) {
textChanged.consume(from);
}
}
@Override
public T onEnter(Runnable onEnter) {
this.onEnter = onEnter;
@@ -224,7 +567,7 @@ public abstract class AbstractGuiTextField<T extends AbstractGuiTextField<T>>
}
@Override
public T onTextChanged(Runnable textChanged) {
public T onTextChanged(Consumer<String> textChanged) {
this.textChanged = textChanged;
return getThis();
}
@@ -240,10 +583,20 @@ public abstract class AbstractGuiTextField<T extends AbstractGuiTextField<T>>
return setHint(I18n.format(hint));
}
@Override
public ReadableColor getTextColor() {
return textColorEnabled;
}
@Override
public T setTextColor(ReadableColor textColor) {
this.textColor = textColor;
wrapped.setTextColor(textColor.getAlpha() << 24 | textColor.getRed() << 16 | textColor.getGreen() << 8 | textColor.getBlue());
this.textColorEnabled = textColor;
return getThis();
}
@Override
public T setTextColorDisabled(ReadableColor textColorDisabled) {
this.textColorDisabled = textColorDisabled;
return getThis();
}
}

View File

@@ -23,24 +23,144 @@
package de.johni0702.minecraft.gui.element;
import de.johni0702.minecraft.gui.function.Focusable;
import de.johni0702.minecraft.gui.utils.Consumer;
import lombok.NonNull;
import org.lwjgl.util.ReadableColor;
public interface IGuiTextField<T extends IGuiTextField<T>> extends GuiElement<T>, Focusable<T> {
T setText(String text);
T setI18nText(String text, Object... args);
String getText();
/**
* Set the text to the specified string.
* If the string is longer than {@link #getMaxLength()} it is truncated from the end.
* This method positions the cursor at the end of the text and removes any selections.
* @param text The new text
* @return {@code this} for chaining
*/
@NonNull T setText(@NonNull String text);
/**
* Set the text to the specified string.
* If the string is longer than {@link #getMaxLength()} it is truncated from the end.
* This method positions the cursor at the end of the text and removes any selections.
* @param text The language key for the new text
* @param args The arguments used in translating the language key
* @return {@code this} for chaining
*/
@NonNull T setI18nText(@NonNull String text, @NonNull Object... args);
/**
* Return the whole text in this text field.
* @return The text, may be empty
*/
@NonNull String getText();
/**
* Return the maximum allowed length of the text in this text field.
* @return Maximum number of characters
*/
int getMaxLength();
/**
* Set the maximum allowed length of the text in this text field.
* If the current test is longer than the new limit, it is truncated from the end (the cursor and selection
* are reset in that process, see {@link #setText(String)}).
* @param maxLength Maximum number of characters
* @return {@code this} for chaining
* @throws IllegalArgumentException When {@code maxLength} is negative
*/
T setMaxLength(int maxLength);
/**
* Deletes the text between {@code from} and {@code to} (inclusive).
* @param from Index at which to start
* @param to Index to which to delete
* @return The deleted text
* @throws IllegalArgumentException If {@code from} is greater than {@code to} or either is out of bounds
*/
@NonNull String deleteText(int from, int to);
/**
* Return the index at which the selection starts (inclusive)
* @return Index of first character
*/
int getSelectionFrom();
/**
* Return the index at which the selection ends (exclusive)
* @return Index after the last character
*/
int getSelectionTo();
/**
* Return the selected text.
* @return The selected text
*/
@NonNull String getSelectedText();
/**
* Delete the selected text. Positions the cursor at the beginning of the selection and clears the selection.
* @return The deleted text
*/
@NonNull String deleteSelectedText();
/**
* Appends the specified string to this text field character by character.
* Excess characters are ignored.
* @param append String to append
* @return {@code this} for chaining
* @see #writeChar(char)
*/
@NonNull T writeText(@NonNull String append);
/**
* Appends the specified character to this text field replacing the current selection (if any).
* This does nothing if the maximum character limit is reached.
* @param c Character to append
* @return {@code this} for chaining
*/
@NonNull T writeChar(char c);
/**
* Delete the nex character (if any).
* Clears the selection.
* @return {@code this} for chaining
*/
T deleteNextChar();
/**
* Delete everything from the cursor (inclusive) to the beginning of the next word (exclusive).
* If there are no more words, delete everything until the end of the line.
* @return The deleted text
*/
String deleteNextWord();
/**
* Delete the previous character (if any).
* @return {@code this} for chaining
*/
@NonNull T deletePreviousChar();
/**
* Delete everything from cursor to the first character of the previous word (or the start of the line).
* @return The deleted text
*/
@NonNull String deletePreviousWord();
/**
* Set the cursor position.
* @param pos Position of the cursor
* @return {@code this} for chaining
* @throws IllegalArgumentException If {@code pos} &lt 0 or pos &gt length
*/
@NonNull T setCursorPosition(int pos);
T onEnter(Runnable onEnter);
T onTextChanged(Runnable textChanged);
T onTextChanged(Consumer<String> textChanged);
String getHint();
T setHint(String hint);
T setI18nHint(String hint, Object... args);
ReadableColor getTextColor();
T setTextColor(ReadableColor textColor);
T setTextColorDisabled(ReadableColor textColorDisabled);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2015 johni0702
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.johni0702.minecraft.gui.utils;
public class Consumers {
public static <U> Consumer<U> from(final Runnable runnable) {
return new Consumer<U>() {
@Override
public void consume(U obj) {
runnable.run();
}
};
}
}