diff --git a/src/main/java/ca/teamdman/sfm/client/screen/text_editor/SFMTextEditScreenV1.java b/src/main/java/ca/teamdman/sfm/client/screen/text_editor/SFMTextEditScreenV1.java index bd12e2ff2..b9c237228 100644 --- a/src/main/java/ca/teamdman/sfm/client/screen/text_editor/SFMTextEditScreenV1.java +++ b/src/main/java/ca/teamdman/sfm/client/screen/text_editor/SFMTextEditScreenV1.java @@ -39,6 +39,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; +import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -440,9 +441,17 @@ public boolean mouseClicked( int button ) { try { - // if mouse in bounds, translate to accommodate line numbers - if (mx >= this.x + 1 && mx <= this.x + this.width - 1) { - mx -= getLineNumberWidth(); + if (button == 0 && this.visible && this.withinContentAreaPoint(mx, my)) { + if (lastProgramWithSyntaxHighlighting.isEmpty()) { + return false; + } + boolean selecting = Screen.hasShiftDown(); + this.textField.setSelecting(selecting); + seekCursorFromPoint(mx, my); + if (!selecting) { + this.textField.selectCursor = this.textField.cursor; + } + return true; } return super.mouseClicked(mx, my, button); } catch (Exception e) { @@ -466,6 +475,24 @@ public boolean mouseDragged( double dx, double dy ) { + try { + if (button == 0 && this.visible && this.withinContentAreaPoint(mx, my)) { + if (lastProgramWithSyntaxHighlighting.isEmpty()) { + return false; + } + boolean shiftDown = Screen.hasShiftDown(); + this.textField.setSelecting(true); + seekCursorFromPoint(mx, my); + this.textField.setSelecting(shiftDown); + if (!shiftDown) { + this.textField.selectCursor = this.textField.cursor; + } + return true; + } + } catch (Exception e) { + SFM.LOGGER.error("Error in SFMTextEditScreenV1.MyMultiLineEditBox.mouseDragged", e); + return false; + } // if mouse in bounds, translate to accommodate line numbers int thisX = SFMScreenRenderUtils.getX(this); if (mx >= thisX + 1 && mx <= thisX + this.width - 1) { @@ -479,6 +506,32 @@ public int getSelectionCursorPosition() { return this.textField.selectCursor; } + private void seekCursorFromPoint(double mx, double my) { + double innerX = mx - (this.x + this.innerPadding() + getLineNumberWidth()); + double innerY = my - (this.y + this.innerPadding()) + this.scrollAmount(); + int lineHeight = this.font.lineHeight; + int lineIndex = Mth.clamp((int) Math.floor(innerY / lineHeight), 0, lastProgramWithSyntaxHighlighting.size() - 1); + int lineStartIndex = getLineStartIndex(lineIndex); + String plainLine = lastProgramWithSyntaxHighlighting.get(lineIndex).getString(); + int clampedX = (int) Math.max(0, innerX); + int cursorOffsetInLine = this.font.plainSubstrByWidth(plainLine, clampedX).length(); + int cursorPosition = Mth.clamp(lineStartIndex + cursorOffsetInLine, 0, this.textField.value().length()); + this.textField.seekCursor(Whence.ABSOLUTE, cursorPosition); + } + + private int getLineStartIndex(int lineIndex) { + String value = this.textField.value(); + int index = 0; + for (int i = 0; i < lineIndex && index < value.length(); i++) { + int newline = value.indexOf('\n', index); + if (newline == -1) { + return value.length(); + } + index = newline + 1; + } + return index; + } + public void setSelectionCursorPosition(int cursor) { this.textField.selectCursor = cursor; } @@ -593,7 +646,8 @@ protected void renderContents( for (int line = 0; line < lines.size(); ++line) { var componentColoured = lines.get(line); - int lineLength = componentColoured.getString().length(); + String plainLine = componentColoured.getString(); + int lineLength = plainLine.length(); int lineHeight = this.font.lineHeight; boolean cursorOnThisLine = isCursorVisible && cursorIndex >= charCount @@ -619,9 +673,12 @@ protected void renderContents( if (cursorOnThisLine) { isCursorAtEndOfLine = cursorIndex == charCount + lineLength; cursorY = lineY; + int relativeCursorIndex = cursorIndex - charCount; + int drawnWidthBeforeCursor = this.font.width(plainLine.substring(0, relativeCursorIndex)); + cursorX = lineX + drawnWidthBeforeCursor; // draw text before cursor - cursorX = SFMFontUtils.drawInBatch( - substring(componentColoured, 0, cursorIndex - charCount), + SFMFontUtils.drawInBatch( + substring(componentColoured, 0, relativeCursorIndex), font, lineX, lineY, @@ -629,11 +686,11 @@ protected void renderContents( false, matrix4f, buffer - ) - 1; + ); SFMTextEditScreenV1.this.suggestedActions.setXY(cursorX + 10, cursorY); // draw text after cursor SFMFontUtils.drawInBatch( - substring(componentColoured, cursorIndex - charCount, lineLength), + substring(componentColoured, relativeCursorIndex, lineLength), font, cursorX, lineY, @@ -661,8 +718,8 @@ protected void renderContents( int lineSelectionStart = Math.max(selectionStart - charCount, 0); int lineSelectionEnd = Math.min(selectionEnd - charCount, lineLength); - int highlightStartX = this.font.width(substring(componentColoured, 0, lineSelectionStart)); - int highlightEndX = this.font.width(substring(componentColoured, 0, lineSelectionEnd)); + int highlightStartX = this.font.width(plainLine.substring(0, lineSelectionStart)); + int highlightEndX = this.font.width(plainLine.substring(0, lineSelectionEnd)); SFMScreenRenderUtils.renderHighlight( poseStack,