Skip to content

Commit

Permalink
updated text area renderer to support '\t' symbol
Browse files Browse the repository at this point in the history
  • Loading branch information
SpinyOwl committed Nov 12, 2017
1 parent 19f6ca7 commit 326a083
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 21 deletions.
Expand Up @@ -82,12 +82,9 @@ public void process(KeyEvent event) {
* @param textArea text area to work with.
*/
private void addTab(TextArea textArea) {
int tabSize = 4;
int oldCPos = textArea.getCaretPosition();
for (int i = 0; i < tabSize; i++) {
textArea.getTextState().insert(oldCPos, " ");
}
int caretPosition = oldCPos + tabSize;
textArea.getTextState().insert(oldCPos, "\t");
int caretPosition = oldCPos + 1;
textArea.setCaretPosition(caretPosition);
textArea.setStartSelectionIndex(caretPosition);
textArea.setEndSelectionIndex(caretPosition);
Expand Down
Expand Up @@ -27,7 +27,7 @@ protected void renderBorder(SimpleLineBorder border, Component component, Contex
Vector2f size = component.getSize();
if (component.isFocused()) {
NvgShapes.drawRectStroke(
nanovg, component.getAbsolutePosition().add(-1f, +1f), size, ColorConstants.red(), 2, cornerRadius);
nanovg, component.getAbsolutePosition().add(-0.5f, +0.5f), size, component.getFocusedStrokeColor(), 0.5f, cornerRadius);
}
NvgShapes.drawRectStroke(
nanovg, component.getAbsolutePosition(), size, borderColor, thickness, cornerRadius);
Expand Down
Expand Up @@ -16,6 +16,7 @@
import static org.lwjgl.system.MemoryUtil.memUTF8;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;
import org.joml.Vector2f;
import org.joml.Vector4f;
Expand All @@ -36,19 +37,23 @@
*/
public class NvgTextAreaRenderer extends NvgDefaultComponentRenderer<TextArea> {

public static final String NEWLINE = "\n";
private static final String PRATIO = "pratio";
private static final String POFFSETX = "poffsetx";
private static final String PHALIGN = "phalign";
private static final String PVALIGN = "pvalign";
private static final String POFFSETY = "poffsety";

private static final int SPACES_PER_TAB = 4;
private static final String TABS = "\t";
private static final String SPACES = " ";
private static final char SPACEC = ' ';
private final Vector4f caretColor = new Vector4f(0, 0, 0, 0.5f);
private final int maxGlyphCount = 2048;


@Override
public void renderSelf(TextArea component, Context context, long nanovg) {
createScissor(nanovg, component); {
createScissor(nanovg, component);
{
Vector2f pos = component.getAbsolutePosition();
Vector2f size = component.getSize();
float br = component.getCornerRadius();
Expand All @@ -62,7 +67,8 @@ public void renderSelf(TextArea component, Context context, long nanovg) {

intersectScissor(nanovg, new Vector4f(intersectRect).sub(1, 1, -2, -2));
renderText(context, nanovg, component, size, intersectRect, bc);
} resetScissor(nanovg);
}
resetScissor(nanovg);
}

private void renderText(Context leguiContext, long context, TextArea gui, Vector2f size, Vector4f rect, Vector4f bc) {
Expand All @@ -82,7 +88,10 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector
int caretLine = 0;
Map<String, Object> metadata = gui.getMetadata();

String[] lines = text.split("\n", -1);
preinitializeTextRendering(context, font, fontSize, halign, valign, textColor);
float spaceWidth = getSpaceWidth(context);

String[] lines = text.split(NEWLINE, -1);
int lineCount = lines.length;
int[] lineStartIndeces = new int[lineCount];
int caretOffset = 0;
Expand Down Expand Up @@ -116,7 +125,6 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector
float mouseY = cursorPosition.y;
float rat = size.y * size.x;

preinitializeTextRendering(context, font, fontSize, halign, valign, textColor);

// we need to calculate x and y offsets
String caretLineText = lines[caretLine];
Expand All @@ -127,7 +135,7 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector

// also we need to calculate offset x // caretLine
float offsetX = 0;
caretx = getCaretx(context, lineCaretPosition, caretLineText, caretLineBounds, glyphs);
caretx = getCaretx(context, lineCaretPosition, caretLineText, caretLineBounds, glyphs, spaceWidth);
offsetX = calculateOffsetX(rect, caretx, offsetX);

Float poffsetx = /*offsetX;//*/(Float) metadata.getOrDefault(POFFSETX, 0f);
Expand All @@ -149,6 +157,9 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector
String line = lines[i];
float[] lineBounds = calculateTextBoundsRect(context, rect, line, halign, valign);
bounds[i] = lineBounds;
if (line.contains(TABS)) {
bounds[i][6] += spaceWidth * (line.length() - line.replace(TABS, "").length()) * (SPACES_PER_TAB - 1);
}
}
// calculate default mouse line index
if (lineCount > 0) {
Expand All @@ -166,7 +177,7 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector

// render selection background
renderSelectionBackground(context, gui, fontSize, focused, highlightColor, lines, lineCount, lineStartIndeces, voffset, poffsetx, poffsety, bounds,
glyphs);
glyphs, spaceWidth);

// render every line of text
for (int i = 0; i < lineCount; i++) {
Expand Down Expand Up @@ -244,8 +255,10 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector
// render current line background
renderCurrentLineBackground(context, rect, bc, fontSize, focused, caretLine, i, lineY);

char[] spaces = new char[SPACES_PER_TAB];
Arrays.fill(spaces, SPACEC);
NvgText.drawTextLineToRect(context, new Vector4f(lineX, lineY, bounds[i][6], bounds[i][7]),
false, HorizontalAlign.LEFT, VerticalAlign.MIDDLE, fontSize, font, line, textColor);
false, HorizontalAlign.LEFT, VerticalAlign.MIDDLE, fontSize, font, line.replace(TABS, new String(spaces)), textColor);
if (i == caretLine && focused) {
// render caret
NvgShapes.drawRectStroke(context, new Vector4f(caretx - poffsetx - 1, lineY, 1, bounds[i][7]), caretColor, 1);
Expand All @@ -269,6 +282,27 @@ private void renderText(Context leguiContext, long context, TextArea gui, Vector
glyphs.free();
}

private float getSpaceWidth(long context) {
String s = SPACES + SPACES;
ByteBuffer spaceBytes = null;
NVGGlyphPosition.Buffer glyphs = NVGGlyphPosition.calloc(maxGlyphCount);
try {
spaceBytes = memUTF8(s);

alignTextInBox(context, HorizontalAlign.LEFT, VerticalAlign.MIDDLE);
nnvgTextGlyphPositions(context, 10, 0, memAddress(spaceBytes), 0, memAddress(glyphs), maxGlyphCount);

float x1 = glyphs.get(1).x();
float x0 = glyphs.get(0).x();
return x1 - x0;
} finally {
if (spaceBytes != null) {
memFree(spaceBytes);
}
glyphs.free();
}
}

private void renderCurrentLineBackground(long context, Vector4f rect, Vector4f bc, float fontSize, boolean focused, int caretLine, int i, float lineY) {
if (i == caretLine && focused) {
Vector4f currentLineBgColor = oppositeBlackOrWhite(bc);
Expand All @@ -278,7 +312,7 @@ private void renderCurrentLineBackground(long context, Vector4f rect, Vector4f b
}

private void renderSelectionBackground(long context, TextArea gui, float fontSize, boolean focused, Vector4f selectionColor, String[] lines, int lineCount,
int[] lineStartIndeces, float voffset, Float poffsetx, Float poffsety, float[][] bounds, NVGGlyphPosition.Buffer glyphs) {
int[] lineStartIndeces, float voffset, Float poffsetx, Float poffsety, float[][] bounds, NVGGlyphPosition.Buffer glyphs, float spaceWidth) {
if (focused) {
int startSelectionIndex = gui.getStartSelectionIndex();
int endSelectionIndex = gui.getEndSelectionIndex();
Expand All @@ -294,18 +328,20 @@ private void renderSelectionBackground(long context, TextArea gui, float fontSiz
int endSelectionLine = 0;
int endSelectionIndexInLine;
for (int i = 0; i < lineCount; i++) {
if (startSelectionIndex > lineStartIndeces[i]) {
if (startSelectionIndex >= lineStartIndeces[i]) {
startSelectionLine = i;
}
if (endSelectionIndex > lineStartIndeces[i]) {
if (endSelectionIndex >= lineStartIndeces[i]) {
endSelectionLine = i;
}
}
startSelectionIndexInLine = startSelectionIndex - lineStartIndeces[startSelectionLine];
endSelectionIndexInLine = endSelectionIndex - lineStartIndeces[endSelectionLine];

float startSelectionCaretX = getCaretx(context, startSelectionIndexInLine, lines[startSelectionLine], bounds[startSelectionLine], glyphs);
float endSelectionCaretX = getCaretx(context, endSelectionIndexInLine, lines[endSelectionLine], bounds[endSelectionLine], glyphs);
float startSelectionCaretX =
getCaretx(context, startSelectionIndexInLine, lines[startSelectionLine], bounds[startSelectionLine], glyphs, spaceWidth);
float endSelectionCaretX =
getCaretx(context, endSelectionIndexInLine, lines[endSelectionLine], bounds[endSelectionLine], glyphs, spaceWidth);

for (int i = 0; i < lineCount; i++) {
if (i >= startSelectionLine && i <= endSelectionLine) {
Expand Down Expand Up @@ -379,7 +415,8 @@ private Float recalculateOffsetY(Vector4f rect, float fontSize, VerticalAlign va
return newPOffsetY;
}

private float getCaretx(long context, int lineCaretPosition, String caretLineText, float[] caretLineBounds, NVGGlyphPosition.Buffer glyphs) {
private float getCaretx(long context, int lineCaretPosition, String caretLineText, float[] caretLineBounds, NVGGlyphPosition.Buffer glyphs,
float spaceWidth) {
float caretx;
ByteBuffer caretLineBytes = null;
try {
Expand All @@ -389,6 +426,15 @@ private float getCaretx(long context, int lineCaretPosition, String caretLineTex
alignTextInBox(context, HorizontalAlign.LEFT, VerticalAlign.MIDDLE);
int ng = nnvgTextGlyphPositions(context, caretLineBounds[4], 0, memAddress(caretLineBytes), 0, memAddress(glyphs), maxGlyphCount);
caretx = calculateCaretPos(lineCaretPosition, caretLineBounds, ng, glyphs);

String substring = caretLineText.substring(0, lineCaretPosition);
int tabCountBeforeCaret = 0;
if (substring.contains(TABS)) {
tabCountBeforeCaret = substring.length() - substring.replace(TABS, "").length();
int i = substring.indexOf(TABS);
float spW = glyphs.get(i + 1).x() - glyphs.get(i).x();
caretx += spaceWidth * tabCountBeforeCaret * (SPACES_PER_TAB - 1);
}
} finally {
memFree(caretLineBytes);
}
Expand Down

0 comments on commit 326a083

Please sign in to comment.