/** * Draw every char in separate terminal cell to guaranty equal width for different lines. * Nevertheless to improve kerning we draw word characters as one block for monospaced fonts. */ private void drawChars(int x, int y, CharBuffer buf, TextStyle style, Graphics2D gfx) { final int blockLen = 1; int offset = 0; int drawCharsOffset = 0; // workaround to fix Swing bad rendering of bold special chars on Linux // TODO required for italic? CharBuffer renderingBuffer; if (mySettingsProvider.DECCompatibilityMode() && style.hasOption(TextStyle.Option.BOLD)) { renderingBuffer = CharUtils.heavyDecCompatibleBuffer(buf); } else { renderingBuffer = buf; } while (offset + blockLen <= buf.length()) { if (renderingBuffer.getBuf()[buf.getStart() + offset] == CharUtils.DWC) { offset += blockLen; drawCharsOffset += blockLen; continue; // dont' draw second part(fake one) of double width character } Font font = getFontToDisplay(buf.charAt(offset + blockLen - 1), style); // while (myMonospaced && (offset + blockLen < buf.getLength()) && // isWordCharacter(buf.charAt(offset + blockLen - 1)) // && (font == getFontToDisplay(buf.charAt(offset + blockLen - 1), style))) { // blockLen++; // } gfx.setFont(font); int descent = gfx.getFontMetrics(font).getDescent(); int baseLine = (y + 1) * myCharSize.height - descent; int xCoord = (x + drawCharsOffset) * myCharSize.width; int textLength = CharUtils.getTextLengthDoubleWidthAware( buf.getBuf(), buf.getStart() + offset, blockLen, mySettingsProvider.ambiguousCharsAreDoubleWidth()); int yCoord = y * myCharSize.height; gfx.setClip( xCoord, yCoord, Math.min(textLength * myCharSize.width, getWidth() - xCoord), Math.min(myCharSize.height, getHeight() - yCoord)); gfx.setColor(getPalette().getColor(myStyleState.getForeground(style.getForegroundForRun()))); gfx.drawChars(renderingBuffer.getBuf(), buf.getStart() + offset, blockLen, xCoord, baseLine); drawCharsOffset += blockLen; offset += blockLen; } gfx.setClip(null); }
private void drawCharacters(int x, int y, TextStyle style, CharBuffer buf, Graphics2D gfx) { int xCoord = x * myCharSize.width; int yCoord = y * myCharSize.height; if (xCoord < 0 || xCoord > getWidth() || yCoord < 0 || yCoord > getHeight()) { return; } gfx.setColor(getPalette().getColor(myStyleState.getBackground(style.getBackgroundForRun()))); int textLength = CharUtils.getTextLengthDoubleWidthAware( buf.getBuf(), buf.getStart(), buf.length(), mySettingsProvider.ambiguousCharsAreDoubleWidth()); gfx.fillRect( xCoord, yCoord, Math.min(textLength * myCharSize.width, getWidth() - xCoord), Math.min(myCharSize.height, getHeight() - yCoord)); if (buf.isNul()) { return; // nothing more to do } drawChars(x, y, buf, style, gfx); gfx.setColor(getPalette().getColor(myStyleState.getForeground(style.getForegroundForRun()))); int baseLine = (y + 1) * myCharSize.height - myDescent; if (style.hasOption(TextStyle.Option.UNDERLINED)) { gfx.drawLine(xCoord, baseLine + 1, (x + textLength) * myCharSize.width, baseLine + 1); } }
private void drawInputMethodUncommitedChars(Graphics2D gfx) { if (myInputMethodUncommitedChars != null && myInputMethodUncommitedChars.length() > 0) { int x = myCursor.getCoordX() * myCharSize.width; int y = (myCursor.getCoordY()) * myCharSize.height - 2; int len = (myInputMethodUncommitedChars.length()) * myCharSize.width; gfx.setColor(getBackground()); gfx.fillRect(x, (myCursor.getCoordY() - 1) * myCharSize.height, len, myCharSize.height); gfx.setColor(getForeground()); gfx.setFont(myNormalFont); gfx.drawString(myInputMethodUncommitedChars, x, y); Stroke saved = gfx.getStroke(); BasicStroke dotted = new BasicStroke( 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, new float[] {0, 2, 0, 2}, 0); gfx.setStroke(dotted); gfx.drawLine(x, y, x + len, y); gfx.setStroke(saved); } }
public void drawCursor(char c, Graphics2D gfx, TextStyle style) { TerminalCursorState state = computeCursorState(); // hidden: do nothing if (state == TerminalCursorState.HIDDEN) { return; } else { final int x = getCoordX(); final int y = getCoordY(); if (y >= 0 && y < myTermSize.height) { if (state == TerminalCursorState.SHOWING) { TextStyle styleToDraw = getInversedStyle(style); drawCharacters(x, y, styleToDraw, new CharBuffer(c, 1), gfx); } else if (state == TerminalCursorState.NO_FOCUS) { int xCoord = x * myCharSize.width; int yCoord = y * myCharSize.height; gfx.setColor( getPalette().getColor(myStyleState.getForeground(style.getForegroundForRun()))); gfx.drawRect(xCoord, yCoord, myCharSize.width - 1, myCharSize.height - 1); } } } }
@Override public void paintComponent(final Graphics g) { final Graphics2D gfx = (Graphics2D) g; setupAntialiasing(gfx); gfx.setColor(getBackground()); gfx.fillRect(0, 0, getWidth(), getHeight()); myTerminalTextBuffer.processHistoryAndScreenLines( myClientScrollOrigin, new StyledTextConsumer() { final int columnCount = getColumnCount(); @Override public void consume( int x, int y, @NotNull TextStyle style, @NotNull CharBuffer characters, int startRow) { int row = y - startRow; drawCharacters(x, row, style, characters, gfx); if (mySelection != null) { Pair<Integer, Integer> interval = mySelection.intersect(x, row + myClientScrollOrigin, characters.length()); if (interval != null) { TextStyle selectionStyle = getSelectionStyle(style); CharBuffer selectionChars = characters.subBuffer(interval.first - x, interval.second); drawCharacters(interval.first, row, selectionStyle, selectionChars, gfx); } } } @Override public void consumeNul( int x, int y, int nulIndex, TextStyle style, CharBuffer characters, int startRow) { int row = y - startRow; if (mySelection != null) { // compute intersection with all NUL areas, non-breaking Pair<Integer, Integer> interval = mySelection.intersect( nulIndex, row + myClientScrollOrigin, columnCount - nulIndex); if (interval != null) { TextStyle selectionStyle = getSelectionStyle(style); drawCharacters(x, row, selectionStyle, characters, gfx); return; } } drawCharacters(x, row, style, characters, gfx); } @Override public void consumeQueue(int x, int y, int nulIndex, int startRow) { if (x < columnCount) { consumeNul( x, y, nulIndex, TextStyle.EMPTY, new CharBuffer(CharUtils.EMPTY_CHAR, columnCount - x), startRow); } } }); int cursorY = myCursor.getCoordY(); if (myClientScrollOrigin + getRowCount() > cursorY) { int cursorX = myCursor.getCoordX(); Pair<Character, TextStyle> sc = myTerminalTextBuffer.getStyledCharAt(cursorX, cursorY); TextStyle normalStyle = sc.second != null ? sc.second : myStyleState.getCurrent(); TextStyle selectionStyle = getSelectionStyle(normalStyle); boolean inSelection = inSelection(cursorX, cursorY); myCursor.drawCursor(sc.first, gfx, inSelection ? selectionStyle : normalStyle); } drawInputMethodUncommitedChars(gfx); drawMargins(gfx, getWidth(), getHeight()); }
private void drawMargins(Graphics2D gfx, int width, int height) { gfx.setColor(getBackground()); gfx.fillRect(0, height, getWidth(), getHeight() - height); gfx.fillRect(width, 0, getWidth() - width, getHeight()); }