fix(CustomSingleLineTextField, CustomMultiLineTextArea): account for trailing spaces when measuring caret and selection positions
This commit is contained in:
@@ -668,6 +668,14 @@ public class CustomMultiLineTextArea extends Component {
|
|||||||
return this.cachedSpaceWidth;
|
return this.cachedSpaceWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int countTrailingSpaces(final String text) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = text.length() - 1; i >= 0 && text.charAt(i) == ' '; i--) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateCaretPosition(final int mouseX, final int mouseY) {
|
private void updateCaretPosition(final int mouseX, final int mouseY) {
|
||||||
final List<String> wrappedLines = getWrappedLines();
|
final List<String> wrappedLines = getWrappedLines();
|
||||||
final List<String> rawLines = getLines();
|
final List<String> rawLines = getLines();
|
||||||
@@ -696,7 +704,8 @@ public class CustomMultiLineTextArea extends Component {
|
|||||||
|
|
||||||
for (int j = 0; j <= clickedLine.length(); j++) {
|
for (int j = 0; j <= clickedLine.length(); j++) {
|
||||||
final String substr = clickedLine.substring(0, j);
|
final String substr = clickedLine.substring(0, j);
|
||||||
final int textWidth = G2DDrawFont.getTextDimensions(substr, this.getGraphics(), this.fontSize, 1.0).getX();
|
final int baseWidth = G2DDrawFont.getTextDimensions(substr, this.getGraphics(), this.fontSize, 1.0).getX();
|
||||||
|
final int textWidth = baseWidth + this.countTrailingSpaces(substr) * this.getSpaceWidth();
|
||||||
final int dist = Math.abs(textWidth - (logicalMouseX - CONTENT_MARGIN));
|
final int dist = Math.abs(textWidth - (logicalMouseX - CONTENT_MARGIN));
|
||||||
if (dist < bestDist) {
|
if (dist < bestDist) {
|
||||||
bestDist = dist;
|
bestDist = dist;
|
||||||
@@ -790,7 +799,8 @@ public class CustomMultiLineTextArea extends Component {
|
|||||||
if (text == null || text.isEmpty()) {
|
if (text == null || text.isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return G2DDrawFont.getTextDimensions(text, g2d, this.fontSize, 1.0).getX();
|
final int baseWidth = G2DDrawFont.getTextDimensions(text, g2d, this.fontSize, 1.0).getX();
|
||||||
|
return baseWidth + this.countTrailingSpaces(text) * this.getSpaceWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderTextSegment(final Graphics2D g2d, final Color color, final int x, final int y, final String text) {
|
private void renderTextSegment(final Graphics2D g2d, final Color color, final int x, final int y, final String text) {
|
||||||
@@ -1074,8 +1084,8 @@ public class CustomMultiLineTextArea extends Component {
|
|||||||
? caretWrappedLine.substring(0, caretPosInWrappedLine)
|
? caretWrappedLine.substring(0, caretPosInWrappedLine)
|
||||||
: "";
|
: "";
|
||||||
final var textDim = beforeCaret.isEmpty() ? ImmutableCoordI2.create(0, 0) : G2DDrawFont.getTextDimensions(beforeCaret, g2d, this.fontSize, this.scaleFactor);
|
final var textDim = beforeCaret.isEmpty() ? ImmutableCoordI2.create(0, 0) : G2DDrawFont.getTextDimensions(beforeCaret, g2d, this.fontSize, this.scaleFactor);
|
||||||
final int spaceWidth = beforeCaret.endsWith(" ") ? getSpaceWidth() : 0;
|
final int trailingSpaceWidth = this.countTrailingSpaces(beforeCaret) * (int) (this.getSpaceWidth() * this.scaleFactor);
|
||||||
final int caretX = textDim.getX() + toScreenCoord(CONTENT_MARGIN) + (int) (spaceWidth * this.scaleFactor);
|
final int caretX = textDim.getX() + toScreenCoord(CONTENT_MARGIN) + trailingSpaceWidth;
|
||||||
final int caretY = (int) ((CONTENT_MARGIN + caretWrappedLineIndex * lineHeight - this.scrollOffsetY) * this.scaleFactor);
|
final int caretY = (int) ((CONTENT_MARGIN + caretWrappedLineIndex * lineHeight - this.scrollOffsetY) * this.scaleFactor);
|
||||||
final int caretHeight = (int) (rawFontHeight * this.scaleFactor);
|
final int caretHeight = (int) (rawFontHeight * this.scaleFactor);
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
|
|
||||||
private int cachedRawFontHeight = 0;
|
private int cachedRawFontHeight = 0;
|
||||||
|
|
||||||
|
private int cachedSpaceWidth = 0;
|
||||||
|
|
||||||
|
private int cachedSpaceWidthFontSize = 0;
|
||||||
|
|
||||||
private final ThemeManager themeManager;
|
private final ThemeManager themeManager;
|
||||||
|
|
||||||
private final Consumer<String> onTextChanged;
|
private final Consumer<String> onTextChanged;
|
||||||
@@ -382,7 +386,8 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
|
|
||||||
for (int j = 0; j <= this.text.length(); j++) {
|
for (int j = 0; j <= this.text.length(); j++) {
|
||||||
final String substr = this.text.substring(0, j);
|
final String substr = this.text.substring(0, j);
|
||||||
final int textWidth = G2DDrawFont.getTextDimensions(substr, this.getGraphics(), this.fontSize, 1.0).getX();
|
final int baseWidth = G2DDrawFont.getTextDimensions(substr, this.getGraphics(), this.fontSize, 1.0).getX();
|
||||||
|
final int textWidth = baseWidth + this.countTrailingSpaces(substr) * this.getSpaceWidth();
|
||||||
final int dist = Math.abs(textWidth - textX);
|
final int dist = Math.abs(textWidth - textX);
|
||||||
if (dist < bestDist) {
|
if (dist < bestDist) {
|
||||||
bestDist = dist;
|
bestDist = dist;
|
||||||
@@ -400,7 +405,8 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String beforeCaret = this.text.substring(0, this.caretPosition);
|
final String beforeCaret = this.text.substring(0, this.caretPosition);
|
||||||
final int caretX = G2DDrawFont.getTextDimensions(beforeCaret, this.getGraphics(), this.fontSize, 1.0).getX();
|
final int baseCaretX = G2DDrawFont.getTextDimensions(beforeCaret, this.getGraphics(), this.fontSize, 1.0).getX();
|
||||||
|
final int caretX = baseCaretX + this.countTrailingSpaces(beforeCaret) * this.getSpaceWidth();
|
||||||
final int visibleWidth = getVisibleWidth();
|
final int visibleWidth = getVisibleWidth();
|
||||||
|
|
||||||
if (caretX < this.scrollOffsetX) {
|
if (caretX < this.scrollOffsetX) {
|
||||||
@@ -418,6 +424,30 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
return (int) (this.getWidth() / this.scaleFactor);
|
return (int) (this.getWidth() / this.scaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getSpaceWidth() {
|
||||||
|
if (this.cachedSpaceWidth > 0 && this.cachedSpaceWidthFontSize == this.fontSize) {
|
||||||
|
return this.cachedSpaceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getGraphics() == null) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int widthWithoutSpace = G2DDrawFont.getTextDimensions("MM", this.getGraphics(), this.fontSize, 1.0).getX();
|
||||||
|
final int widthWithSpace = G2DDrawFont.getTextDimensions("M M", this.getGraphics(), this.fontSize, 1.0).getX();
|
||||||
|
this.cachedSpaceWidth = widthWithSpace - widthWithoutSpace;
|
||||||
|
this.cachedSpaceWidthFontSize = this.fontSize;
|
||||||
|
return this.cachedSpaceWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countTrailingSpaces(final String text) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = text.length() - 1; i >= 0 && text.charAt(i) == ' '; i--) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
private int toLogicalCoord(final int screenCoord) {
|
private int toLogicalCoord(final int screenCoord) {
|
||||||
return (int) (screenCoord / this.scaleFactor);
|
return (int) (screenCoord / this.scaleFactor);
|
||||||
}
|
}
|
||||||
@@ -574,8 +604,11 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
final String selected = this.text.substring(selStart, selEnd);
|
final String selected = this.text.substring(selStart, selEnd);
|
||||||
final String afterSel = this.text.substring(selEnd);
|
final String afterSel = this.text.substring(selEnd);
|
||||||
|
|
||||||
final int beforeSelWidth = G2DDrawFont.getTextDimensions(beforeSel, g2d, this.fontSize, this.scaleFactor).getX();
|
final int baseBeforeSelWidth = G2DDrawFont.getTextDimensions(beforeSel, g2d, this.fontSize, this.scaleFactor).getX();
|
||||||
final int selWidth = G2DDrawFont.getTextDimensions(selected, g2d, this.fontSize, this.scaleFactor).getX();
|
final int baseSelWidth = G2DDrawFont.getTextDimensions(selected, g2d, this.fontSize, this.scaleFactor).getX();
|
||||||
|
final int spaceWidthScaled = (int) (this.getSpaceWidth() * this.scaleFactor);
|
||||||
|
final int beforeSelWidth = baseBeforeSelWidth + this.countTrailingSpaces(beforeSel) * spaceWidthScaled;
|
||||||
|
final int selWidth = baseSelWidth + this.countTrailingSpaces(selected) * spaceWidthScaled;
|
||||||
final int drawOffsetX = TEXT_PADDING - (int) (this.scrollOffsetX * this.scaleFactor);
|
final int drawOffsetX = TEXT_PADDING - (int) (this.scrollOffsetX * this.scaleFactor);
|
||||||
|
|
||||||
if (!beforeSel.isEmpty()) {
|
if (!beforeSel.isEmpty()) {
|
||||||
@@ -615,7 +648,8 @@ public class CustomSingleLineTextField extends Component {
|
|||||||
final var textDim = beforeCaret.isEmpty()
|
final var textDim = beforeCaret.isEmpty()
|
||||||
? ImmutableCoordI2.create(0, 0)
|
? ImmutableCoordI2.create(0, 0)
|
||||||
: G2DDrawFont.getTextDimensions(beforeCaret, g2d, this.fontSize, this.scaleFactor);
|
: G2DDrawFont.getTextDimensions(beforeCaret, g2d, this.fontSize, this.scaleFactor);
|
||||||
final int caretX = textDim.getX() + TEXT_PADDING - (int) (this.scrollOffsetX * this.scaleFactor);
|
final int trailingSpaceWidth = this.countTrailingSpaces(beforeCaret) * (int) (this.getSpaceWidth() * this.scaleFactor);
|
||||||
|
final int caretX = textDim.getX() + trailingSpaceWidth + TEXT_PADDING - (int) (this.scrollOffsetX * this.scaleFactor);
|
||||||
final int caretY = (int) (textY * this.scaleFactor);
|
final int caretY = (int) (textY * this.scaleFactor);
|
||||||
final int caretHeight = (int) (rawFontHeight * this.scaleFactor);
|
final int caretHeight = (int) (rawFontHeight * this.scaleFactor);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user