/** * Returns a list of pairs of x coordinates for visual ranges representing given logical range. If * <code>startOffset == endOffset</code>, a pair of equal numbers is returned, corresponding to * target position. Target offsets are supposed to be located on the same visual line. */ private TFloatArrayList logicalRangeToVisualRanges(int startOffset, int endOffset) { assert startOffset <= endOffset; TFloatArrayList result = new TFloatArrayList(); for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, startOffset, false)) { int minOffset = fragment.getMinOffset(); int maxOffset = fragment.getMaxOffset(); if (startOffset == endOffset) { if (startOffset >= minOffset && startOffset <= maxOffset) { float x = fragment.offsetToX(startOffset); result.add(x); result.add(x); break; } } else if (startOffset < maxOffset && endOffset > minOffset) { float x1 = fragment.offsetToX(Math.max(minOffset, startOffset)); float x2 = fragment.offsetToX(Math.min(maxOffset, endOffset)); if (x1 > x2) { float tmp = x1; x1 = x2; x2 = tmp; } if (result.isEmpty() || x1 > result.get(result.size() - 1)) { result.add(x1); result.add(x2); } else { result.set(result.size() - 1, x2); } } } return result; }
private void paintWhitespace( Graphics2D g, CharSequence text, float x, int y, int start, int end, EditorImpl.LineWhitespacePaintingStrategy whitespacePaintingStrategy, VisualLineFragmentsIterator.Fragment fragment) { g.setColor(myEditor.getColorsScheme().getColor(EditorColors.WHITESPACES_COLOR)); boolean isRtl = fragment.isRtl(); int baseStartOffset = fragment.getStartOffset(); int startOffset = isRtl ? baseStartOffset - start : baseStartOffset + start; for (int i = start; i < end; i++) { int charOffset = isRtl ? baseStartOffset - i - 1 : baseStartOffset + i; char c = text.charAt(charOffset); if (" \t\u3000".indexOf(c) >= 0 && whitespacePaintingStrategy.showWhitespaceAtOffset(charOffset)) { int startX = (int) fragment.offsetToX( x, startOffset, isRtl ? baseStartOffset - i : baseStartOffset + i); int endX = (int) fragment.offsetToX( x, startOffset, isRtl ? baseStartOffset - i - 1 : baseStartOffset + i + 1); if (c == ' ') { g.fillRect((startX + endX) / 2, y, 1, 1); } else if (c == '\t') { endX -= myView.getPlainSpaceWidth() / 4; int height = myView.getCharHeight(); int halfHeight = height / 2; int mid = y - halfHeight; int top = y - height; UIUtil.drawLine(g, startX, mid, endX, mid); UIUtil.drawLine(g, endX, y, endX, top); g.fillPolygon( new int[] {endX - halfHeight, endX - halfHeight, endX}, new int[] {y, y - height, y - halfHeight}, 3); } else if (c == '\u3000') { // ideographic space final int charHeight = myView.getCharHeight(); g.drawRect(startX + 2, y - charHeight, endX - startX - 4, charHeight); } } } }
private void paintLineFragments( Graphics2D g, Rectangle clip, int visualLine, int y, LineFragmentPainter painter) { float x = visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0; int offset = myView.visualPositionToOffset(new VisualPosition(visualLine, 0)); int visualLineEndOffset = myView.visualPositionToOffset(new VisualPosition(visualLine, Integer.MAX_VALUE, true)); IterationState it = null; int prevEndOffset = -1; boolean firstFragment = true; int maxColumn = 0; for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) { int fragmentStartOffset = fragment.getStartOffset(); int start = fragmentStartOffset; int end = fragment.getEndOffset(); x = fragment.getStartX(); if (firstFragment) { firstFragment = false; SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset); if (softWrap != null) { prevEndOffset = offset; it = new IterationState( myEditor, offset == 0 ? 0 : offset - 1, visualLineEndOffset, true, false, false, false); if (it.getEndOffset() <= offset) { it.advance(); } painter.paintBeforeLineStart( g, it.getStartOffset() == offset ? it.getBeforeLineStartBackgroundAttributes() : it.getMergedAttributes(), fragment.getStartVisualColumn(), fragment.getStartX(), y); } } FoldRegion foldRegion = fragment.getCurrentFoldRegion(); if (foldRegion == null) { if (start != prevEndOffset) { it = new IterationState( myEditor, start, fragment.isRtl() ? offset : visualLineEndOffset, true, false, false, fragment.isRtl()); } prevEndOffset = end; assert it != null; while (fragment.isRtl() ? start > end : start < end) { if (fragment.isRtl() ? it.getEndOffset() >= start : it.getEndOffset() <= start) { assert !it.atEnd(); it.advance(); } TextAttributes attributes = it.getMergedAttributes(); int curEnd = fragment.isRtl() ? Math.max(it.getEndOffset(), end) : Math.min(it.getEndOffset(), end); float xNew = fragment.offsetToX(x, start, curEnd); painter.paint( g, fragment, fragment.isRtl() ? fragmentStartOffset - start : start - fragmentStartOffset, fragment.isRtl() ? fragmentStartOffset - curEnd : curEnd - fragmentStartOffset, attributes, x, xNew, y); x = xNew; start = curEnd; } } else { float xNew = fragment.getEndX(); painter.paint( g, fragment, 0, fragment.getEndVisualColumn() - fragment.getStartVisualColumn(), getFoldRegionAttributes(foldRegion), x, xNew, y); x = xNew; prevEndOffset = -1; it = null; } maxColumn = fragment.getEndVisualColumn(); } if (it == null || it.getEndOffset() != visualLineEndOffset) { it = new IterationState( myEditor, visualLineEndOffset == offset ? visualLineEndOffset : visualLineEndOffset - 1, visualLineEndOffset, true, false, false, false); } if (!it.atEnd()) { it.advance(); } assert it.atEnd(); painter.paintAfterLineEnd(g, clip, it, maxColumn, x, y); }