diff --git a/src/main/java/com/cleanroommc/modularui/widgets/textfield/BaseTextFieldWidget.java b/src/main/java/com/cleanroommc/modularui/widgets/textfield/BaseTextFieldWidget.java index 6a3e5856b..98817661b 100644 --- a/src/main/java/com/cleanroommc/modularui/widgets/textfield/BaseTextFieldWidget.java +++ b/src/main/java/com/cleanroommc/modularui/widgets/textfield/BaseTextFieldWidget.java @@ -285,7 +285,8 @@ public void onMouseDrag(int mouseButton, long timeSinceClick) { } else if (Interactable.isKeyComboCtrlV(keyCode)) { this.handler.deleteMarked(); // paste copied text in marked text - this.handler.insert(GuiScreen.getClipboardString().replace("§", ""), canScrollHorizontally()); + String clipboard = GuiScreen.getClipboardString().replace("§", "").replace("\r", ""); + this.handler.insert(clipboard, canScrollHorizontally()); return Result.SUCCESS; } else if (Interactable.isKeyComboCtrlX(keyCode) && this.handler.hasTextMarked()) { // copy and delete copied text @@ -408,6 +409,19 @@ public W hintColor(int color) { return getThis(); } + public String getText() { + return this.handler.getTextAsString(); + } + + public List getTextLines() { + return this.handler.getText(); + } + + public W setText(String text) { + this.handler.setText(text); + return getThis(); + } + public static char getDecimalSeparator() { return format.getDecimalFormatSymbols().getDecimalSeparator(); } diff --git a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldHandler.java b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldHandler.java index 3f28b4f28..1b272836c 100644 --- a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldHandler.java +++ b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldHandler.java @@ -36,6 +36,7 @@ public class TextFieldHandler { public TextFieldHandler(BaseTextFieldWidget textFieldWidget) { this.textFieldWidget = textFieldWidget; + ensureNotEmpty(); } public void setPattern(@Nullable Pattern pattern) { @@ -137,6 +138,7 @@ public void setCursor(Point cursor, boolean animate) { } private void clampCursor(Point p) { + ensureNotEmpty(); p.y = MathUtils.clamp(p.y, 0, this.text.size() - 1); String line = this.text.get(p.y); p.x = MathUtils.clamp(p.x, 0, line.length()); @@ -245,13 +247,17 @@ public void moveCursorEnd(boolean ctrl, boolean shift) { } public void markAll() { + ensureNotEmpty(); setOffsetCursor(0, 0); - setMainCursor(this.text.size() - 1, this.text.get(this.text.size() - 1).length(), true); + int last = this.text.size() - 1; + setMainCursor(last, this.text.get(last).length(), true); } public void markCurrentLine() { - setOffsetCursor(getMainCursor().y, 0); - setMainCursor(getMainCursor().y, this.text.get(getMainCursor().y).length(), true); + ensureNotEmpty(); + int lineY = MathUtils.clamp(getMainCursor().y, 0, this.text.size() - 1); + setOffsetCursor(lineY, 0); + setMainCursor(lineY, this.text.get(lineY).length(), true); } public String getTextAsString() { @@ -276,11 +282,15 @@ public void onChanged() { } public String getSelectedText() { - if (!hasTextMarked()) return ""; + if (!hasTextMarked() || this.text.isEmpty()) return ""; Point min = getStartCursor(); Point max = getEndCursor(); + + if (min.y < 0 || max.y >= this.text.size()) return ""; + if (min.y == max.y) { - return this.text.get(min.y).substring(min.x, max.x); + String line = this.text.get(min.y); + return line.substring(MathUtils.clamp(min.x, 0, line.length()), MathUtils.clamp(max.x, 0, line.length())); } StringBuilder builder = new StringBuilder(); builder.append(this.text.get(min.y).substring(min.x)).append("\n"); @@ -298,14 +308,22 @@ public boolean test(String text) { } public void insert(String text, boolean hasHorizontalScrolling) { + if (text == null) return; + text = text.replace("\r", ""); + insert(Arrays.asList(text.split("\n")), hasHorizontalScrolling); } public void insert(List text, boolean hasHorizontalScrolling) { List copy = new ArrayList<>(this.text); Point point = insert(copy, text); - // if we can scroll horizontally, we have virtually an infinite amount of space and don't need to check width - if (point == null || copy.size() > this.maxLines || !this.renderer.wouldFit(copy, !hasHorizontalScrolling)) return; + + if (point == null || copy.size() > this.maxLines) return; + + if (this.maxLines == 1 && !this.renderer.wouldFit(copy, !hasHorizontalScrolling)) { + return; + } + this.text.clear(); this.text.addAll(copy); setCursor(point, true); @@ -346,7 +364,7 @@ private Point insert(List text, List insertion) { x = insertion.get(insertion.size() - 1).length(); y += 1; if (insertion.size() > 2) { - text.addAll(this.cursor.y + 1, text.subList(1, insertion.size() - 1)); + text.addAll(this.cursor.y + 1, insertion.subList(1, insertion.size() - 1)); y += insertion.size() - 2; } return new Point(x, y); @@ -365,6 +383,8 @@ public void newLine() { public void clear() { markAll(); deleteMarked(); + ensureNotEmpty(); + setCursor(0, 0, true); } public void deleteMarked() { @@ -378,6 +398,11 @@ public void delete(boolean ctrl, boolean shift) { } public void delete(boolean inFront, boolean ctrl, boolean shift) { + if (this.text.isEmpty()) { + setCursor(0, 0, false); + return; + } + if (hasTextMarked()) { Point min = getStartCursor(); Point max = getEndCursor(); @@ -393,7 +418,8 @@ public void delete(boolean inFront, boolean ctrl, boolean shift) { } setCursor(min.y, min.x, false); } else { - String line = this.text.get(this.cursor.y); + int lineIdx = MathUtils.clamp(this.cursor.y, 0, this.text.size() - 1); + String line = this.text.get(lineIdx); if (inFront) { if (this.cursor.x == line.length()) { if (this.text.size() > this.cursor.y + 1) { @@ -438,9 +464,30 @@ public void delete(boolean inFront, boolean ctrl, boolean shift) { if (this.scrollArea != null) { this.scrollArea.getScrollX().clamp(this.scrollArea); } + ensureNotEmpty(); onChanged(); } + public void ensureNotEmpty() { + if (this.text.isEmpty()) { + this.text.add(""); + } + } + + public void setText(String text) { + clear(); + if (text != null && !text.isEmpty()) { + insert(text, false); + } + } + + public void setText(List lines) { + clear(); + if (lines != null && !lines.isEmpty()) { + insert(lines, false); + } + } + public void setMaxLines(int maxLines) { this.maxLines = Math.max(1, maxLines); } diff --git a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldRenderer.java b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldRenderer.java index 8f6ebc96c..7bfb89539 100644 --- a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldRenderer.java +++ b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldRenderer.java @@ -86,14 +86,21 @@ public void draw(List lines) { protected void drawMeasuredLines(List measuredLines) { drawMarked(measuredLines); super.drawMeasuredLines(measuredLines); - // draw cursor + + if (measuredLines.isEmpty() || this.handler.getText().isEmpty()) return; + if (this.renderCursor && !this.simulate) { Point main = this.handler.getMainCursor(); - Point2D.Float start = getPosOf(measuredLines, main); - if (this.handler.getText().get(main.y).isEmpty()) { - start.x += 0.7f; + + if (main.y >= 0 && main.y < this.handler.getText().size()) { + Point2D.Float start = getPosOf(measuredLines, main); + if (start != null) { + if (this.handler.getText().get(main.y).isEmpty()) { + start.x += 0.7f; + } + drawCursor(start.x, start.y); + } } - drawCursor(start.x, start.y); } } @@ -103,6 +110,17 @@ public List wrapLine(String line) { } protected void drawMarked(List measuredLines) { + if (measuredLines.isEmpty() || !this.handler.hasTextMarked()) { + return; + } + + int min = this.handler.getStartCursor().y; + int max = this.handler.getEndCursor().y; + + if (min < 0 || max >= measuredLines.size()) { + return; + } + if (!this.simulate && this.handler.hasTextMarked()) { Point2D.Float start = getPosOf(measuredLines, this.handler.getStartCursor()); // render Marked @@ -111,8 +129,7 @@ protected void drawMarked(List measuredLines) { if (start.y == end.y) { drawMarked(start.y, start.x, end.x); } else { - int min = this.handler.getStartCursor().y; - int max = this.handler.getEndCursor().y; + Line line = measuredLines.get(min); int startX = getStartX(line.getWidth()); drawMarked(start.y, start.x, startX + line.getWidth()); @@ -185,7 +202,7 @@ private int getRealLength(String text) { } public Point2D.Float getPosOf(List measuredLines, Point cursorPos) { - if (measuredLines.isEmpty()) { + if (measuredLines.isEmpty() || cursorPos.y < 0 || cursorPos.y >= measuredLines.size()) { return new Point2D.Float(getStartX(0), getStartYOfLines(1)); } Line line = measuredLines.get(cursorPos.y); diff --git a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldWidget.java b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldWidget.java index 53c91d82b..097e48341 100644 --- a/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldWidget.java +++ b/src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldWidget.java @@ -123,21 +123,15 @@ public void drawForeground(ModularGuiContext context) { @NotNull public String getText() { - if (this.handler.getText().isEmpty()) { - return ""; - } if (this.handler.getText().size() > 1) { throw new IllegalStateException("TextFieldWidget can only have one line!"); } return this.handler.getText().get(0); } - public void setText(@NotNull String text) { - if (this.handler.getText().isEmpty()) { - this.handler.getText().add(text); - } else { - this.handler.getText().set(0, text); - } + public TextFieldWidget setText(String text) { + this.handler.setText(text); + return this; } /**