paint caret directionality mark

This commit is contained in:
Dmitry Batrak
2015-05-26 16:07:44 +03:00
parent eb5273de5a
commit 125b0ef148
4 changed files with 87 additions and 32 deletions
@@ -4607,10 +4607,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private void setCursorPosition() {
final List<CaretRectangle> caretPoints = new ArrayList<CaretRectangle>();
for (Caret caret : getCaretModel().getAllCarets()) {
boolean isRtl = myUseNewRendering && myView.isRtlLocation(caret.getOffset());
VisualPosition caretPosition = caret.getVisualPosition();
Point pos1 = visualPositionToXY(caretPosition);
Point pos2 = visualPositionToXY(new VisualPosition(caretPosition.line, caretPosition.column + 1));
caretPoints.add(new CaretRectangle(pos1, pos2.x - pos1.x, caret));
Point pos2 = visualPositionToXY(new VisualPosition(caretPosition.line, Math.max(0, caretPosition.column + (isRtl ? -1 : 1))));
caretPoints.add(new CaretRectangle(pos1, Math.abs(pos2.x - pos1.x), caret, isRtl));
}
myCaretCursor.setPositions(caretPoints.toArray(new CaretRectangle[caretPoints.size()]));
}
@@ -4681,11 +4682,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
public final Point myPoint;
public final int myWidth;
public final Caret myCaret;
public final boolean myIsRtl;
private CaretRectangle(Point point, int width, Caret caret) {
private CaretRectangle(Point point, int width, Caret caret, boolean isRtl) {
myPoint = point;
myWidth = Math.max(width, 2);
myCaret = caret;
myIsRtl = isRtl;
}
}
@@ -4698,7 +4701,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private long myStartTime = 0;
private CaretCursor() {
myLocations = new CaretRectangle[] {new CaretRectangle(new Point(0, 0), 0, null)};
myLocations = new CaretRectangle[] {new CaretRectangle(new Point(0, 0), 0, null, false)};
setEnabled(true);
}
@@ -4743,8 +4746,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
private void repaint() {
for (CaretRectangle location : myLocations) {
myEditorComponent.repaintEditorComponent(location.myPoint.x, location.myPoint.y, location.myWidth, getLineHeight());
if (myUseNewRendering) {
myView.repaintCarets();
}
else {
for (CaretRectangle location : myLocations) {
myEditorComponent.repaintEditorComponent(location.myPoint.x, location.myPoint.y, location.myWidth, getLineHeight());
}
}
}
@@ -52,6 +52,7 @@ class EditorPainter {
private static final Color CARET_DARK = Gray._0;
private static final Stroke IME_COMPOSED_TEXT_UNDERLINE_STROKE = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0,
new float[]{0, 2, 0, 2}, 0);
private static final int CARET_DIRECTION_MARK_SIZE = 5;
private final EditorView myView;
private final EditorImpl myEditor;
@@ -636,46 +637,69 @@ class EditorPainter {
}
}
private void paintCaret(Graphics2D g) {
private void paintCaret(Graphics2D g_) {
EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations();
if (locations == null) return;
for (EditorImpl.CaretRectangle location : locations) {
paintCaretAt(g, location.myPoint.x, location.myPoint.y, location.myWidth, location.myCaret);
}
}
private void paintCaretAt(Graphics2D g_, int x, int y, int width, Caret caret) {
Graphics2D g = IdeBackgroundUtil.getOriginalGraphics(g_);
int lineHeight = myView.getLineHeight();
EditorSettings settings = myEditor.getSettings();
Color caretColor = myEditor.getColorsScheme().getColor(EditorColors.CARET_COLOR);
if (caretColor == null) caretColor = new JBColor(CARET_DARK, CARET_LIGHT);
g.setColor(caretColor);
if (myEditor.isInsertMode() != settings.isBlockCursor()) {
if (UIUtil.isRetina()) {
g.fillRect(x, y, settings.getLineCursorWidth(), lineHeight);
} else {
for (int i = 0; i < settings.getLineCursorWidth(); i++) {
UIUtil.drawLine(g, x + i, y, x + i, y + lineHeight - 1);
for (EditorImpl.CaretRectangle location : locations) {
int x = location.myPoint.x;
int y = location.myPoint.y;
Caret caret = location.myCaret;
boolean isRtl = location.myIsRtl;
if (myEditor.isInsertMode() != settings.isBlockCursor()) {
int lineWidth = settings.getLineCursorWidth();
g.fillRect(x, y, lineWidth, lineHeight);
if (myDocument.getTextLength() > 0 && caret != null && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) {
g.fillPolygon(new int[]{
isRtl ? x + lineWidth - 1 : x,
isRtl ? x + lineWidth - 1 - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE,
isRtl ? x + lineWidth - 1 : x
},
new int[]{y, y, y + CARET_DIRECTION_MARK_SIZE}, 3);
}
}
}
else {
g.fillRect(Math.min(x, x + width), y, Math.abs(width), lineHeight - 1);
int targetVisualColumn = caret.getVisualPosition().column;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart())) {
int startVisualColumn = fragment.getStartVisualColumn();
int endVisualColumn = fragment.getEndVisualColumn();
if (startVisualColumn <= targetVisualColumn && endVisualColumn > targetVisualColumn) {
g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK);
fragment.draw(g, x, y + myView.getAscent(), targetVisualColumn - startVisualColumn, targetVisualColumn - startVisualColumn + 1);
break;
else {
int width = location.myWidth;
int startX = Math.max(0, isRtl ? x - width : x);
g.fillRect(startX, y, width, lineHeight - 1);
if (myDocument.getTextLength() > 0 && caret != null) {
int targetVisualColumn = caret.getVisualPosition().column;
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, caret.getVisualLineStart())) {
int startVisualColumn = fragment.getStartVisualColumn();
int endVisualColumn = fragment.getEndVisualColumn();
if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn ||
startVisualColumn == targetVisualColumn && !isRtl ||
endVisualColumn == targetVisualColumn && isRtl) {
g.setColor(ColorUtil.isDark(caretColor) ? CARET_LIGHT : CARET_DARK);
fragment.draw(g, startX, y + myView.getAscent(),
targetVisualColumn - startVisualColumn - (isRtl ? 1 : 0),
targetVisualColumn - startVisualColumn + (isRtl ? 0 : 1));
break;
}
}
}
}
}
}
void repaintCarets() {
EditorImpl.CaretRectangle[] locations = myEditor.getCaretLocations();
if (locations == null) return;
int lineHeight = myView.getLineHeight();
for (EditorImpl.CaretRectangle location : locations) {
int x = location.myPoint.x;
int y = location.myPoint.y;
int width = Math.max(location.myWidth, CARET_DIRECTION_MARK_SIZE);
myEditor.getContentComponent().repaintEditorComponent(x - width, y, width * 2, lineHeight);
}
}
private void paintLineFragments(Graphics2D g, Rectangle clip, int visualLine, int y, LineFragmentPainter painter) {
float x = visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0;
LogicalPosition logicalPosition = myView.visualToLogicalPosition(new VisualPosition(visualLine, 0), false);
@@ -198,6 +198,11 @@ public class EditorView implements Disposable {
myPainter.paint(g);
}
public void repaintCarets() {
assertIsDispatchThread();
myPainter.repaintCarets();
}
public Dimension getPreferredSize() {
assertIsDispatchThread();
return mySizeManager.getPreferredSize();
@@ -254,6 +259,13 @@ public class EditorView implements Disposable {
mySizeManager.reset();
myTextLayoutCache.resetToDocumentSize();
}
public boolean isRtlLocation(int offset) {
if (myDocument.getTextLength() == 0) return false;
int line = myDocument.getLineNumber(offset);
LineLayout layout = getLineLayout(line);
return layout.isRtlLocation(offset - myDocument.getLineStartOffset(line));
}
@NotNull
LineLayout getLineLayout(int line) {
@@ -200,6 +200,17 @@ class LineLayout {
};
}
boolean isLtr() {
return myBidiRunsInLogicalOrder.length == 0 || myBidiRunsInLogicalOrder.length == 1 && !myBidiRunsInLogicalOrder[0].isRtl();
}
boolean isRtlLocation(int offset) {
for (BidiRun run : myBidiRunsInLogicalOrder) {
if (offset < run.endOffset) return run.isRtl();
}
return false;
}
private static class BidiRun {
private final byte level;
private final int startOffset;