From 70447a8719b6d8d5ad3ac0da2a5610eef77df9c4 Mon Sep 17 00:00:00 2001 From: nea Date: Sat, 30 Oct 2021 02:49:38 +0200 Subject: [PATCH 1/4] Refactor rendering of WTextField and add text scrolling --- .../github/cottonmc/test/TestDescription.java | 4 +- .../cotton/gui/widget/WTextField.java | 384 +++++++++--------- 2 files changed, 197 insertions(+), 191 deletions(-) diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java b/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java index 5cf09d4d..70c50d49 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java @@ -18,7 +18,7 @@ public class TestDescription extends SyncedGuiDescription { public TestDescription(ScreenHandlerType type, int syncId, PlayerInventory playerInventory, ScreenHandlerContext context) { super(type, syncId, playerInventory, getBlockInventory(context, GuiBlockEntity.INVENTORY_SIZE), null); - + WGridPanel root = (WGridPanel)this.getRootPanel(); WItemSlot slot = WItemSlot.of(blockInventory, 0, 4, 1); @@ -39,7 +39,7 @@ public TestDescription(ScreenHandlerType type, int syncId, PlayerInventory pl root.add(buttonB, 5, 3, 4, 1); root.add(new WButton(new LiteralText("Button C")), 0, 5, 4, 1); root.add(new WButton(new LiteralText("Button D")), 5, 5, 4, 1); - root.add(new WTextField(new LiteralText("Type something...")), 0, 7, 5, 1); + root.add(new WTextField(new LiteralText("Type something...")).setMaxLength(64), 0, 7, 5, 1); root.add(new WLabel(new LiteralText("Large slot:")), 0, 9); root.add(WItemSlot.outputOf(blockInventory, 0), 4, 9); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java index e9e26927..c0ef7c2f 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java @@ -33,63 +33,82 @@ import java.util.function.Predicate; public class WTextField extends WWidget { - public static final int OFFSET_X_TEXT = 4; - //public static final int OFFSET_Y_TEXT = 6; - + public static final int TEXT_PADDING_X = 4; + public static final int TEXT_PADDING_Y = 6; + public static final int CURSOR_PADDING_Y = 4; + public static final int CURSOR_HEIGHT = 12; + @Environment(EnvType.CLIENT) private TextRenderer font; private String text = ""; private int maxLength = 16; private boolean editable = true; + private int tickCount = 0; + + private int disabledColor = 0x707070; private int enabledColor = 0xE0E0E0; - private int uneditableColor = 0x707070; - + private int suggestionColor = 0x808080; + + private static final int BACKGROUND_COLOR = 0xFF000000; + private static final int BORDER_COLOR_SELECTED = 0xFFFFFFA0; + private static final int BORDER_COLOR_UNSELECTED = 0xFFA0A0A0; + private static final int CURSOR_COLOR = 0xFFD0D0D0; + @Nullable private Text suggestion = null; + + // Index of the leftmost character to be rendered. + private int scrollOffset = 0; + private int cursor = 0; /** - * If not -1, select is the "anchor point" of a selection. That is, if you hit shift+left with - * no existing selection, the selection will be anchored to where you were, but the cursor will - * move left, expanding the selection as you continue to move left. If you move to the right, - * eventually you'll overtake the anchor, drop the anchor at the same place and start expanding - * the selection rightwards instead. + * If not -1, select is the "anchor point" of a selection. That is, if you hit shift+left with no existing + * selection, the selection will be anchored to where you were, but the cursor will move left, expanding the + * selection as you continue to move left. If you move to the right, eventually you'll overtake the anchor, drop the + * anchor at the same place and start expanding the selection rightwards instead. */ private int select = -1; private Consumer onChanged; private Predicate textPredicate; - + @Environment(EnvType.CLIENT) @Nullable private BackgroundPainter backgroundPainter; public WTextField() { } - + public WTextField(Text suggestion) { this.suggestion = suggestion; } - + public void setText(String s) { - if (this.textPredicate==null || this.textPredicate.test(s)) { - this.text = (s.length()>maxLength) ? s.substring(0,maxLength) : s; - if (onChanged!=null) onChanged.accept(this.text); + if (this.textPredicate == null || this.textPredicate.test(s)) { + this.text = (s.length() > maxLength) ? s.substring(0, maxLength) : s; + if (onChanged != null) onChanged.accept(this.text); } } public String getText() { return this.text; } - + @Override public boolean canResize() { return true; } - + + @Override + public void tick() { + super.tick(); + this.tickCount++; + } + @Override public void setSize(int x, int y) { super.setSize(x, 20); @@ -97,6 +116,7 @@ public void setSize(int x, int y) { public void setCursorPos(int location) { this.cursor = MathHelper.clamp(location, 0, this.text.length()); + scrollCursorIntoView(); } public int getMaxLength() { @@ -106,112 +126,103 @@ public int getMaxLength() { public int getCursor() { return this.cursor; } - + + public void scrollCursorIntoView() { + if (scrollOffset > cursor) { + scrollOffset = cursor; + } + if (scrollOffset < cursor && font.trimToWidth(text.substring(scrollOffset), width - TEXT_PADDING_X * 2).length() + scrollOffset < cursor) { + scrollOffset = cursor; + } + + int rightMostScrollOffset = text.length() - font.trimToWidth(text, width - TEXT_PADDING_X * 2, true).length(); + scrollOffset = Math.min(rightMostScrollOffset, scrollOffset); + } + @Nullable public String getSelection() { - if (select<0) return null; - if (select==cursor) return null; - + if (select < 0) return null; + if (select == cursor) return null; + //Tidy some things - if (select>text.length()) select = text.length(); - if (cursor<0) cursor = 0; - if (cursor>text.length()) cursor = text.length(); - + if (select > text.length()) select = text.length(); + if (cursor < 0) cursor = 0; + if (cursor > text.length()) cursor = text.length(); + int start = Math.min(select, cursor); int end = Math.max(select, cursor); - + return text.substring(start, end); } - + public boolean isEditable() { return this.editable; } @Environment(EnvType.CLIENT) - protected void renderTextField(MatrixStack matrices, int x, int y) { - if (this.font==null) this.font = MinecraftClient.getInstance().textRenderer; - - int borderColor = (this.isFocused()) ? 0xFF_FFFFA0 : 0xFF_A0A0A0; - ScreenDrawing.coloredRect(matrices, x-1, y-1, width+2, height+2, borderColor); - ScreenDrawing.coloredRect(matrices, x, y, width, height, 0xFF000000); - - - int textColor = this.editable ? this.enabledColor : this.uneditableColor; - - //TODO: Scroll offset - String trimText = font.trimToWidth(this.text, this.width-OFFSET_X_TEXT); - - boolean selection = (select!=-1); - boolean focused = this.isFocused(); //this.isFocused() && this.focusedTicks / 6 % 2 == 0 && boolean_1; //Blinks the cursor - - //int textWidth = font.getStringWidth(trimText); - //int textAnchor = (font.isRightToLeft()) ? - // x + OFFSET_X_TEXT + textWidth : - // x + OFFSET_X_TEXT; - - int textX = x + OFFSET_X_TEXT; - //(font.isRightToLeft()) ? - //textAnchor - textWidth : - //textAnchor; - - int textY = y + (height - 8) / 2; - - //TODO: Adjust by scroll offset - int adjustedCursor = this.cursor; - if (adjustedCursor > trimText.length()) { - adjustedCursor = trimText.length(); - } - - int preCursorAdvance = textX; - if (!trimText.isEmpty()) { - String string_2 = trimText.substring(0,adjustedCursor); - preCursorAdvance = font.drawWithShadow(matrices, string_2, textX, textY, textColor); - } + protected void renderBox(MatrixStack matrices, int x, int y) { + int borderColor = this.isFocused() ? BORDER_COLOR_SELECTED : BORDER_COLOR_UNSELECTED; + ScreenDrawing.coloredRect(matrices, x - 1, y - 1, width + 2, height + 2, borderColor); + ScreenDrawing.coloredRect(matrices, x, y, width, height, BACKGROUND_COLOR); + } - if (adjustedCursor this.scrollOffset + visibleText.length()) return; + int cursorOffset = this.font.getWidth(visibleText.substring(0, this.cursor - this.scrollOffset)); + ScreenDrawing.coloredRect(matrices, x + TEXT_PADDING_X + cursorOffset, y + CURSOR_PADDING_Y, 1, CURSOR_HEIGHT, CURSOR_COLOR); + } - //int var10002; - //int var10003; - if (focused && !selection) { - if (adjustedCursor scrollOffset + textLength) return; + + int normalizedLeft = Math.max(scrollOffset, left) - scrollOffset; + int normalizedRight = Math.min(scrollOffset + textLength, right) - scrollOffset; + + int leftCaret = font.getWidth(visibleText.substring(0, normalizedLeft)); + int selectionWidth = font.getWidth(visibleText.substring(normalizedLeft, normalizedRight)); + + invertedRect(matrices, x + TEXT_PADDING_X + leftCaret, y + CURSOR_PADDING_Y, selectionWidth, CURSOR_HEIGHT); + } + + @Environment(EnvType.CLIENT) + protected void renderTextField(MatrixStack matrices, int x, int y) { + if (this.font == null) this.font = MinecraftClient.getInstance().textRenderer; + + String visibleText = font.trimToWidth(this.text.substring(this.scrollOffset), this.width - 2 * TEXT_PADDING_X); + renderBox(matrices, x, y); + renderText(matrices, x, y, visibleText); + if (this.text.isEmpty() && !this.isFocused()) { + renderSuggestion(matrices, x, y); } + if (this.isFocused()) { + renderCursor(matrices, x, y, visibleText); + } + renderSelection(matrices, x, y, visibleText); } - + @Environment(EnvType.CLIENT) private void invertedRect(MatrixStack matrices, int x, int y, int width, int height) { Tessellator tessellator = Tessellator.getInstance(); @@ -223,10 +234,10 @@ private void invertedRect(MatrixStack matrices, int x, int y, int width, int hei RenderSystem.enableColorLogicOp(); RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE); buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION); - buffer.vertex(model, x, y+height, 0).next(); - buffer.vertex(model, x+width, y+height, 0).next(); - buffer.vertex(model, x+width, y, 0).next(); - buffer.vertex(model, x, y, 0).next(); + buffer.vertex(model, x, y + height, 0).next(); + buffer.vertex(model, x + width, y + height, 0).next(); + buffer.vertex(model, x + width, y, 0).next(); + buffer.vertex(model, x, y, 0).next(); buffer.end(); BufferRenderer.draw(buffer); RenderSystem.disableColorLogicOp(); @@ -237,12 +248,12 @@ public WTextField setTextPredicate(Predicate predicate_1) { this.textPredicate = predicate_1; return this; } - + public WTextField setChangedListener(Consumer listener) { this.onChanged = listener; return this; } - + public WTextField setMaxLength(int max) { this.maxLength = max; if (this.text.length() > max) { @@ -251,17 +262,22 @@ public WTextField setMaxLength(int max) { } return this; } - + public WTextField setEnabledColor(int col) { this.enabledColor = col; return this; } - + + public WTextField setSuggestionColor(int suggestionColor) { + this.suggestionColor = suggestionColor; + return this; + } + public WTextField setDisabledColor(int col) { - this.uneditableColor = col; + this.disabledColor = col; return this; } - + public WTextField setEditable(boolean editable) { this.editable = editable; return this; @@ -281,17 +297,17 @@ public WTextField setSuggestion(@Nullable Text suggestion) { this.suggestion = suggestion; return this; } - + @Environment(EnvType.CLIENT) public WTextField setBackgroundPainter(BackgroundPainter painter) { this.backgroundPainter = painter; return this; } - + public boolean canFocus() { return true; } - + @Override public void onFocusGained() { } @@ -306,26 +322,28 @@ public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { @Override public InputResult onClick(int x, int y, int button) { requestFocus(); - cursor = getCaretPos(this.text, x-OFFSET_X_TEXT); + cursor = getCaretPos(this.text, x - TEXT_PADDING_X); + scrollCursorIntoView(); return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @Override public void onCharTyped(char ch) { - if (this.text.length()this.text.length()) cursor = this.text.length(); - + if (cursor < 0) cursor = 0; + if (cursor > this.text.length()) cursor = this.text.length(); + String before = this.text.substring(0, cursor); String after = this.text.substring(cursor, this.text.length()); - this.text = before+ch+after; + this.text = before + ch + after; cursor++; + scrollCursorIntoView(); if (onChanged != null) onChanged.accept(text); } } - + @Environment(EnvType.CLIENT) @Override public void onKeyPressed(int ch, int key, int modifiers) { @@ -333,40 +351,40 @@ public void onKeyPressed(int ch, int key, int modifiers) { if (Screen.isCopy(ch)) { String selection = getSelection(); - if (selection!=null) { + if (selection != null) { MinecraftClient.getInstance().keyboard.setClipboard(selection); } - + return; } else if (Screen.isPaste(ch)) { - if (select!=-1) { + if (select != -1) { int a = select; int b = cursor; - if (bthis.maxLength) { + if (text.length() > this.maxLength) { text = text.substring(0, maxLength); - if (cursor>text.length()) cursor = text.length(); + if (cursor > text.length()) cursor = text.length(); } } - + scrollCursorIntoView(); if (onChanged != null) onChanged.accept(text); return; } else if (Screen.isSelectAll(ch)) { @@ -374,66 +392,67 @@ public void onKeyPressed(int ch, int key, int modifiers) { cursor = text.length(); return; } - + //System.out.println("Ch: "+ch+", Key: "+key+", Mod: "+modifiers); - - if (modifiers==0) { - if (ch==GLFW.GLFW_KEY_DELETE || ch==GLFW.GLFW_KEY_BACKSPACE) { - if (text.length()>0 && cursor>0) { - if (select>=0 && select!=cursor) { + + if (modifiers == 0) { + if (ch == GLFW.GLFW_KEY_DELETE || ch == GLFW.GLFW_KEY_BACKSPACE) { + if (text.length() > 0 && cursor > 0) { + if (select >= 0 && select != cursor) { int a = select; int b = cursor; - if (b0) cursor--; + if (cursor > 0) cursor--; } - } else if (ch==GLFW.GLFW_KEY_RIGHT) { - if (select!=-1) { + } else if (ch == GLFW.GLFW_KEY_RIGHT) { + if (select != -1) { cursor = Math.max(cursor, select); select = -1; //Clear the selection anchor } else { - if (cursor0) cursor--; - if (select==cursor) select = -1; - } else if (ch==GLFW.GLFW_KEY_RIGHT) { - if (select==-1) select = cursor; - if (cursor 0) cursor--; + if (select == cursor) select = -1; + } else if (ch == GLFW.GLFW_KEY_RIGHT) { + if (select == -1) select = cursor; + if (cursor < text.length()) cursor++; + if (select == cursor) select = -1; } } } + scrollCursorIntoView(); } @Override @@ -446,41 +465,28 @@ public void addNarrations(NarrationMessageBuilder builder) { } /** - * From an X offset past the left edge of a TextRenderer.draw, finds out what the closest caret - * position (division between letters) is. + * From an X offset past the left edge of a TextRenderer.draw, finds out what the closest caret position (division + * between letters) is. + * * @param s * @param x + * * @return */ @Environment(EnvType.CLIENT) public static int getCaretPos(String s, int x) { - if (x<=0) return 0; - + if (x <= 0) return 0; + TextRenderer font = MinecraftClient.getInstance().textRenderer; int lastAdvance = 0; - for(int i=0; i Date: Sat, 30 Oct 2021 03:14:28 +0200 Subject: [PATCH 2/4] Make caret position movable by clicks Also deprecated the public getCaretPos method since it was public. --- .../cotton/gui/widget/WTextField.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java index c0ef7c2f..3ea21230 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java @@ -127,6 +127,7 @@ public int getCursor() { return this.cursor; } + @Environment(EnvType.CLIENT) public void scrollCursorIntoView() { if (scrollOffset > cursor) { scrollOffset = cursor; @@ -322,11 +323,28 @@ public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { @Override public InputResult onClick(int x, int y, int button) { requestFocus(); - cursor = getCaretPos(this.text, x - TEXT_PADDING_X); + cursor = getCaretPosition(x - TEXT_PADDING_X); scrollCursorIntoView(); return InputResult.PROCESSED; } + @Environment(EnvType.CLIENT) + public int getCaretPosition(int clickX) { + if (clickX < 0) return 0; + int lastPos = 0; + String string = text.substring(scrollOffset); + for (int i = 0; i < string.length(); i++) { + int w = font.getWidth(string.charAt(i) + ""); + if (lastPos + w >= clickX) { + if (clickX - lastPos < w / 2) { + return i + scrollOffset; + } + } + lastPos += w; + } + return string.length(); + } + @Environment(EnvType.CLIENT) @Override public void onCharTyped(char ch) { @@ -474,6 +492,7 @@ public void addNarrations(NarrationMessageBuilder builder) { * @return */ @Environment(EnvType.CLIENT) + @Deprecated public static int getCaretPos(String s, int x) { if (x <= 0) return 0; From 56f354e4f764458a79ef5df02115160cf7d3ff30 Mon Sep 17 00:00:00 2001 From: nea Date: Sat, 30 Oct 2021 04:06:11 +0200 Subject: [PATCH 3/4] Rework keyboard interactions with WTextField Introduce CTRL+(Left/Right) for deletes, selects and cursor moves. --- .../cotton/gui/widget/WTextField.java | 216 +++++++++--------- 1 file changed, 114 insertions(+), 102 deletions(-) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java index 3ea21230..c290124c 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java @@ -348,127 +348,139 @@ public int getCaretPosition(int clickX) { @Environment(EnvType.CLIENT) @Override public void onCharTyped(char ch) { - if (this.text.length() < this.maxLength) { - //snap cursor into bounds if it went astray - if (cursor < 0) cursor = 0; - if (cursor > this.text.length()) cursor = this.text.length(); - - String before = this.text.substring(0, cursor); - String after = this.text.substring(cursor, this.text.length()); - this.text = before + ch + after; - cursor++; - scrollCursorIntoView(); - if (onChanged != null) onChanged.accept(text); + insertText(ch + ""); + } + + @Environment(EnvType.CLIENT) + private void insertText(String toInsert) { + String before, after; + if (select != -1 && select != cursor) { + int left = Math.min(cursor, select); + int right = Math.max(cursor, select); + before = this.text.substring(0, left); + after = this.text.substring(right); + } else { + before = this.text.substring(0, cursor); + after = this.text.substring(cursor); } + if (before.length() + after.length() + toInsert.length() > maxLength) return; + text = before + toInsert + after; + select = -1; + cursor = (before + toInsert).length(); + scrollCursorIntoView(); } @Environment(EnvType.CLIENT) - @Override - public void onKeyPressed(int ch, int key, int modifiers) { - if (!this.editable) return; + private void copySelection() { + String selection = getSelection(); + if (selection != null) { + MinecraftClient.getInstance().keyboard.setClipboard(selection); + } + } - if (Screen.isCopy(ch)) { - String selection = getSelection(); - if (selection != null) { - MinecraftClient.getInstance().keyboard.setClipboard(selection); + @Environment(EnvType.CLIENT) + private void paste() { + String clip = MinecraftClient.getInstance().keyboard.getClipboard(); + insertText(clip); + } + + @Environment(EnvType.CLIENT) + private void deleteSelection() { + int left = Math.min(cursor, select); + int right = Math.max(cursor, select); + text = text.substring(0, left) + text.substring(right); + select = -1; + cursor = left; + scrollCursorIntoView(); + } + + @Environment(EnvType.CLIENT) + private void delete(int modifiers, boolean backwards) { + if (select == -1 || select == cursor) { + select = skipCharaters((GLFW.GLFW_MOD_CONTROL & modifiers) != 0, backwards ? -1 : 1); + } + deleteSelection(); + } + + @Environment(EnvType.CLIENT) + private int skipCharaters(boolean skipMany, int direction) { + if (direction != -1 && direction != 1) return cursor; + int position = cursor; + while (true) { + position += direction; + if (position < 0) { + return 0; + } + if (position > text.length()) { + return text.length(); + } + if (!skipMany) return position; + if (position < text.length() && Character.isWhitespace(text.charAt(position))) { + return position; } + } + } - return; - } else if (Screen.isPaste(ch)) { + @Environment(EnvType.CLIENT) + public void onDirectionalKey(int direction, int modifiers) { + if ((GLFW.GLFW_MOD_SHIFT & modifiers) != 0) { + if (select == -1 || select == cursor) select = cursor; + cursor = skipCharaters((GLFW.GLFW_MOD_CONTROL & modifiers) != 0, direction); + } else { if (select != -1) { - int a = select; - int b = cursor; - if (b < a) { - int tmp = b; - b = a; - a = tmp; - } - String before = this.text.substring(0, a); - String after = this.text.substring(b); - - String clip = MinecraftClient.getInstance().keyboard.getClipboard(); - text = before + clip + after; + cursor = direction < 0 ? Math.min(cursor, select) : Math.max(cursor, select); select = -1; - cursor = (before + clip).length(); } else { - String before = this.text.substring(0, cursor); - String after = this.text.substring(cursor, this.text.length()); - - String clip = MinecraftClient.getInstance().keyboard.getClipboard(); - text = before + clip + after; - cursor += clip.length(); - if (text.length() > this.maxLength) { - text = text.substring(0, maxLength); - if (cursor > text.length()) cursor = text.length(); - } + cursor = skipCharaters((GLFW.GLFW_MOD_CONTROL & modifiers) != 0, direction); } - scrollCursorIntoView(); - if (onChanged != null) onChanged.accept(text); + } + } + + @Environment(EnvType.CLIENT) + @Override + public void onKeyPressed(int ch, int key, int modifiers) { + + if (Screen.isCopy(ch)) { + copySelection(); return; - } else if (Screen.isSelectAll(ch)) { + } + if (Screen.isPaste(ch)) { + paste(); + return; + } + if (Screen.isSelectAll(ch)) { select = 0; cursor = text.length(); return; } - //System.out.println("Ch: "+ch+", Key: "+key+", Mod: "+modifiers); - - if (modifiers == 0) { - if (ch == GLFW.GLFW_KEY_DELETE || ch == GLFW.GLFW_KEY_BACKSPACE) { - if (text.length() > 0 && cursor > 0) { - if (select >= 0 && select != cursor) { - int a = select; - int b = cursor; - if (b < a) { - int tmp = b; - b = a; - a = tmp; - } - String before = this.text.substring(0, a); - String after = this.text.substring(b); - text = before + after; - if (cursor == b) cursor = a; - select = -1; - } else { - String before = this.text.substring(0, cursor); - String after = this.text.substring(cursor, this.text.length()); - - before = before.substring(0, before.length() - 1); - text = before + after; - cursor--; - } - - if (onChanged != null) onChanged.accept(text); + switch (ch) { + case GLFW.GLFW_KEY_DELETE: + delete(modifiers, false); + break; + case GLFW.GLFW_KEY_BACKSPACE: + delete(modifiers, true); + break; + case GLFW.GLFW_KEY_LEFT: + onDirectionalKey(-1, modifiers); + break; + case GLFW.GLFW_KEY_RIGHT: + onDirectionalKey(1, modifiers); + break; + case GLFW.GLFW_KEY_HOME: + case GLFW.GLFW_KEY_UP: + if ((GLFW.GLFW_MOD_SHIFT & modifiers) == 0) { + select = -1; } - } else if (ch == GLFW.GLFW_KEY_LEFT) { - if (select != -1) { - cursor = Math.min(cursor, select); - select = -1; //Clear the selection anchor - } else { - if (cursor > 0) cursor--; + cursor = 0; + break; + case GLFW.GLFW_KEY_END: + case GLFW.GLFW_KEY_DOWN: + if ((GLFW.GLFW_MOD_SHIFT & modifiers) == 0) { + select = -1; } - } else if (ch == GLFW.GLFW_KEY_RIGHT) { - if (select != -1) { - cursor = Math.max(cursor, select); - select = -1; //Clear the selection anchor - } else { - if (cursor < text.length()) cursor++; - } - } else { - //System.out.println("Ch: "+ch+", Key: "+key); - } - } else { - if (modifiers == GLFW.GLFW_MOD_SHIFT) { - if (ch == GLFW.GLFW_KEY_LEFT) { - if (select == -1) select = cursor; - if (cursor > 0) cursor--; - if (select == cursor) select = -1; - } else if (ch == GLFW.GLFW_KEY_RIGHT) { - if (select == -1) select = cursor; - if (cursor < text.length()) cursor++; - if (select == cursor) select = -1; - } - } + cursor = text.length(); + break; } scrollCursorIntoView(); } From b248b4744ae2038fbeb5ded0a03ce641cdbed26e Mon Sep 17 00:00:00 2001 From: nea Date: Fri, 12 Nov 2021 23:28:49 +0100 Subject: [PATCH 4/4] Revert breaking API changes in WTextField --- .../cotton/gui/widget/WTextField.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java index c290124c..ed07f0bc 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java @@ -33,6 +33,12 @@ import java.util.function.Predicate; public class WTextField extends WWidget { + /** + * Use TEXT_PADDING_X instead. + */ + @Deprecated(forRemoval = true) + public static final int OFFSET_X_TEXT = 4; + public static final int TEXT_PADDING_X = 4; public static final int TEXT_PADDING_Y = 6; public static final int CURSOR_PADDING_Y = 4; @@ -504,7 +510,7 @@ public void addNarrations(NarrationMessageBuilder builder) { * @return */ @Environment(EnvType.CLIENT) - @Deprecated + @Deprecated(forRemoval = true) public static int getCaretPos(String s, int x) { if (x <= 0) return 0; @@ -520,4 +526,21 @@ public static int getCaretPos(String s, int x) { return s.length(); } + + /** + * From a caret position, finds out what the x-offset to draw the caret is. + * @param s + * @param pos + * @return + */ + @Environment(EnvType.CLIENT) + @Deprecated(forRemoval = true) + public static int getCaretOffset(String s, int pos) { + if (pos==0) return 0;//-1; + + TextRenderer font = MinecraftClient.getInstance().textRenderer; + int ofs = font.getWidth(s.substring(0, pos))+1; + return ofs; //(font.isRightToLeft()) ? -ofs : ofs; + } + }