2024-06-27 18:03:50 +03:00
|
|
|
package codechicken.nei;
|
|
|
|
|
|
|
|
|
|
import net.minecraft.client.gui.FontRenderer;
|
|
|
|
|
import net.minecraft.client.gui.Gui;
|
|
|
|
|
import net.minecraft.client.gui.GuiTextField;
|
|
|
|
|
import net.minecraft.client.renderer.Tessellator;
|
2025-03-24 16:48:11 +02:00
|
|
|
import net.minecraft.util.ChatAllowedCharacters;
|
2024-06-27 18:03:50 +03:00
|
|
|
import net.minecraft.util.EnumChatFormatting;
|
|
|
|
|
|
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
|
|
2024-07-26 18:44:54 +03:00
|
|
|
public class FormattedTextField extends GuiTextField {
|
2024-06-27 18:03:50 +03:00
|
|
|
|
|
|
|
|
public static interface TextFormatter {
|
|
|
|
|
|
|
|
|
|
TextFormatter DEFAULT = (text) -> text;
|
|
|
|
|
|
|
|
|
|
public String format(String text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected FontRenderer fontRenderer;
|
|
|
|
|
protected String rawText = "";
|
|
|
|
|
protected String formattedText = "";
|
2025-05-12 17:40:42 +03:00
|
|
|
protected String placeholder = "";
|
2024-06-27 18:03:50 +03:00
|
|
|
protected boolean editable = true;
|
|
|
|
|
protected int editableColor = 14737632;
|
|
|
|
|
protected int notEditableColor = 7368816;
|
|
|
|
|
protected TextFormatter formatter = TextFormatter.DEFAULT;
|
|
|
|
|
protected int lineScrollOffset = 0;
|
|
|
|
|
protected int frame = 0;
|
|
|
|
|
|
|
|
|
|
public FormattedTextField(FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height) {
|
|
|
|
|
super(fontRenderer, xPosition, yPosition, width, height);
|
|
|
|
|
this.fontRenderer = fontRenderer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setFormatter(TextFormatter formatter) {
|
|
|
|
|
this.formatter = formatter;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-04 16:59:51 +03:00
|
|
|
public TextFormatter getFormatter() {
|
|
|
|
|
return this.formatter;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
public void setPlaceholder(String placeholder) {
|
|
|
|
|
this.placeholder = placeholder;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 18:03:50 +03:00
|
|
|
@Override
|
|
|
|
|
public void updateCursorCounter() {
|
|
|
|
|
super.updateCursorCounter();
|
|
|
|
|
++this.frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setFocused(boolean focus) {
|
|
|
|
|
if (focus && !this.isFocused()) {
|
|
|
|
|
this.frame = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
super.setFocused(focus);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-25 16:20:28 +03:00
|
|
|
@Override
|
|
|
|
|
public void setText(String rawText) {
|
|
|
|
|
super.setText(EnumChatFormatting.getTextWithoutFormattingCodes(rawText));
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 18:03:50 +03:00
|
|
|
@Override
|
|
|
|
|
public void setSelectionPos(int p_146199_1_) {
|
|
|
|
|
String text = this.getText();
|
|
|
|
|
int j = text.length();
|
|
|
|
|
|
|
|
|
|
super.setSelectionPos(p_146199_1_);
|
|
|
|
|
|
|
|
|
|
p_146199_1_ = Math.max(0, Math.min(p_146199_1_, j));
|
|
|
|
|
|
|
|
|
|
if (this.fontRenderer != null) {
|
|
|
|
|
|
|
|
|
|
if (this.lineScrollOffset > j) {
|
|
|
|
|
this.lineScrollOffset = j;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int k = this.getWidth();
|
|
|
|
|
String s = this.fontRenderer.trimStringToWidth(text.substring(this.lineScrollOffset), k);
|
|
|
|
|
int l = s.length() + this.lineScrollOffset;
|
|
|
|
|
|
|
|
|
|
if (p_146199_1_ == this.lineScrollOffset) {
|
|
|
|
|
this.lineScrollOffset -= this.fontRenderer.trimStringToWidth(text, k, true).length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p_146199_1_ > l) {
|
|
|
|
|
this.lineScrollOffset += p_146199_1_ - l;
|
|
|
|
|
} else if (p_146199_1_ <= this.lineScrollOffset) {
|
|
|
|
|
this.lineScrollOffset -= this.lineScrollOffset - p_146199_1_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.lineScrollOffset = Math.max(0, Math.min(this.lineScrollOffset, j));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setTextColor(int p_146193_1_) {
|
|
|
|
|
super.setTextColor(p_146193_1_);
|
|
|
|
|
this.editableColor = p_146193_1_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setDisabledTextColour(int p_146204_1_) {
|
|
|
|
|
super.setDisabledTextColour(p_146204_1_);
|
|
|
|
|
this.notEditableColor = p_146204_1_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setEnabled(boolean p_146184_1_) {
|
|
|
|
|
super.setEnabled(p_146184_1_);
|
|
|
|
|
this.editable = p_146184_1_;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
protected boolean beforeWrite(String text) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-24 16:48:11 +02:00
|
|
|
@Override
|
2025-05-12 17:40:42 +03:00
|
|
|
public void writeText(String textPart) {
|
2025-03-24 16:48:11 +02:00
|
|
|
String newText = "";
|
2025-05-12 17:40:42 +03:00
|
|
|
String substr = ChatAllowedCharacters.filerAllowedCharacters(textPart);
|
2025-03-24 16:48:11 +02:00
|
|
|
int cursorPosition = getCursorPosition();
|
|
|
|
|
int maxStringLength = getMaxStringLength();
|
|
|
|
|
String text = getText();
|
|
|
|
|
|
|
|
|
|
if (text.isEmpty()) {
|
|
|
|
|
newText = substr.substring(0, Math.min(maxStringLength, substr.length()));
|
|
|
|
|
cursorPosition = newText.length();
|
|
|
|
|
} else {
|
|
|
|
|
int selectionEnd = getSelectionEnd();
|
|
|
|
|
String textStart = text.substring(0, Math.min(cursorPosition, selectionEnd));
|
|
|
|
|
String textEnd = text.substring(Math.max(cursorPosition, selectionEnd));
|
|
|
|
|
newText = textStart + substr + textEnd;
|
|
|
|
|
|
|
|
|
|
if (newText.length() > maxStringLength) {
|
|
|
|
|
newText = newText.substring(0, maxStringLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursorPosition = Math.min(textStart.length() + substr.length(), newText.length());
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (beforeWrite(newText)) {
|
|
|
|
|
setText(newText);
|
|
|
|
|
setCursorPosition(cursorPosition);
|
|
|
|
|
}
|
2025-03-24 16:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getNthWordFromPos(int p_146183_1_, int p_146183_2_) {
|
|
|
|
|
return this.func_146197_a(p_146183_1_, p_146183_2_, true);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 18:03:50 +03:00
|
|
|
@Override
|
|
|
|
|
public void drawTextBox() {
|
|
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (!this.getVisible()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (this.getEnableBackgroundDrawing()) {
|
|
|
|
|
drawRect(
|
|
|
|
|
this.xPosition - 1,
|
|
|
|
|
this.yPosition - 1,
|
|
|
|
|
this.xPosition + this.width + 1,
|
|
|
|
|
this.yPosition + this.height + 1,
|
|
|
|
|
-6250336);
|
|
|
|
|
drawRect(
|
|
|
|
|
this.xPosition,
|
|
|
|
|
this.yPosition,
|
|
|
|
|
this.xPosition + this.width,
|
|
|
|
|
this.yPosition + this.height,
|
|
|
|
|
-16777216);
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (!this.rawText.equals(getText())) {
|
|
|
|
|
this.rawText = getText();
|
|
|
|
|
this.formattedText = this.formatter.format(this.rawText);
|
|
|
|
|
if (!EnumChatFormatting.getTextWithoutFormattingCodes(this.formattedText).toLowerCase()
|
|
|
|
|
.equals(this.rawText.toLowerCase())) {
|
|
|
|
|
this.formattedText = this.rawText;
|
2024-06-27 18:03:50 +03:00
|
|
|
}
|
2025-05-12 17:40:42 +03:00
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (!isFocused() && this.formattedText.isEmpty()) {
|
|
|
|
|
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
|
|
|
|
|
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
|
|
|
|
|
this.fontRenderer.drawStringWithShadow(
|
|
|
|
|
this.fontRenderer.trimStringToWidth(this.placeholder, this.getWidth()),
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
this.notEditableColor);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
int firstCharacterIndex = getFormattedTextShift(this.lineScrollOffset);
|
|
|
|
|
String rawTextClipped = this.fontRenderer
|
|
|
|
|
.trimStringToWidth(this.rawText.substring(this.lineScrollOffset), this.getWidth());
|
|
|
|
|
String textClipped = this.formattedText
|
|
|
|
|
.substring(firstCharacterIndex, getFormattedTextShift(this.lineScrollOffset + rawTextClipped.length()));
|
|
|
|
|
int cursorPosition = getFormattedTextShift(getCursorPosition());
|
|
|
|
|
int selectionEnd = getFormattedTextShift(getSelectionEnd());
|
|
|
|
|
|
|
|
|
|
int color = this.editable ? this.editableColor : this.notEditableColor;
|
|
|
|
|
int cursorA = cursorPosition - firstCharacterIndex;
|
|
|
|
|
int cursorB = selectionEnd - firstCharacterIndex;
|
|
|
|
|
boolean flag = cursorA >= 0 && cursorA <= textClipped.length();
|
|
|
|
|
boolean flag1 = isFocused() && this.frame / 6 % 2 == 0 && flag;
|
|
|
|
|
boolean flag2 = getCursorPosition() < this.rawText.length() || this.rawText.length() >= getMaxStringLength();
|
|
|
|
|
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
|
|
|
|
|
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
|
|
|
|
|
int x2 = x;
|
|
|
|
|
|
|
|
|
|
if (cursorB > textClipped.length()) {
|
|
|
|
|
cursorB = textClipped.length();
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (textClipped.length() > 0) {
|
|
|
|
|
String s1 = flag ? textClipped.substring(0, cursorA) : textClipped;
|
|
|
|
|
String colorA = getPreviousColor(firstCharacterIndex);
|
|
|
|
|
x2 = this.fontRenderer.drawStringWithShadow(colorA + s1, x, y, color);
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
int k1 = x2;
|
2024-06-27 18:03:50 +03:00
|
|
|
|
2025-05-12 17:40:42 +03:00
|
|
|
if (!flag) {
|
|
|
|
|
k1 = cursorA > 0 ? x + this.width : x;
|
|
|
|
|
} else if (flag2) {
|
|
|
|
|
k1 = x2 - 1;
|
|
|
|
|
--x2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (textClipped.length() > 0 && flag && cursorA < textClipped.length()) {
|
|
|
|
|
String colorB = getPreviousColor(firstCharacterIndex + cursorA);
|
|
|
|
|
this.fontRenderer.drawStringWithShadow(colorB + textClipped.substring(cursorA), x2, y, color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flag1) {
|
|
|
|
|
if (flag2) {
|
|
|
|
|
Gui.drawRect(k1, y - 1, k1 + 1, y + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
|
|
|
|
|
} else {
|
|
|
|
|
this.fontRenderer.drawStringWithShadow("_", k1, y, color);
|
2024-06-27 18:03:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-12 17:40:42 +03:00
|
|
|
|
|
|
|
|
if (cursorB != cursorA) {
|
|
|
|
|
int l1 = x + this.fontRenderer.getStringWidth(textClipped.substring(0, cursorB));
|
|
|
|
|
drawCursorVertical(k1, y - 1, l1 - 1, y + 1 + this.fontRenderer.FONT_HEIGHT);
|
|
|
|
|
}
|
2024-06-27 18:03:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void drawCursorVertical(int x1, int y1, int x2, int y2) {
|
|
|
|
|
int i1;
|
|
|
|
|
|
|
|
|
|
if (x1 < x2) {
|
|
|
|
|
i1 = x1;
|
|
|
|
|
x1 = x2;
|
|
|
|
|
x2 = i1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (y1 < y2) {
|
|
|
|
|
i1 = y1;
|
|
|
|
|
y1 = y2;
|
|
|
|
|
y2 = i1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x2 > this.xPosition + this.width) {
|
|
|
|
|
x2 = this.xPosition + this.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x1 > this.xPosition + this.width) {
|
|
|
|
|
x1 = this.xPosition + this.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Tessellator tessellator = Tessellator.instance;
|
2026-03-07 16:58:30 +02:00
|
|
|
GL11.glColor4f(0.0F, 0.0F, 1.0F, 1.0F);
|
2024-06-27 18:03:50 +03:00
|
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
|
|
|
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
|
|
|
|
|
GL11.glLogicOp(GL11.GL_OR_REVERSE);
|
|
|
|
|
tessellator.startDrawingQuads();
|
|
|
|
|
tessellator.addVertex((double) x1, (double) y2, 0.0D);
|
|
|
|
|
tessellator.addVertex((double) x2, (double) y2, 0.0D);
|
|
|
|
|
tessellator.addVertex((double) x2, (double) y1, 0.0D);
|
|
|
|
|
tessellator.addVertex((double) x1, (double) y1, 0.0D);
|
|
|
|
|
tessellator.draw();
|
|
|
|
|
GL11.glDisable(GL11.GL_COLOR_LOGIC_OP);
|
|
|
|
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getFormattedTextShift(int position) {
|
|
|
|
|
int shift = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < position; i++) {
|
|
|
|
|
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
|
|
|
|
|
shift += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return position + shift;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getPreviousColor(int position) {
|
|
|
|
|
while (position >= 0) {
|
|
|
|
|
if (this.formattedText.charAt(position) == '\u00a7') {
|
|
|
|
|
return this.formattedText.substring(position, position + 2);
|
|
|
|
|
}
|
|
|
|
|
position--;
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|