From dab33831cb3783fd4af4db7e4aebfbc3eb774368 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Sat, 24 Feb 2018 12:05:05 +0800 Subject: [PATCH] feat: current line highlight --- .../main/assets/editor/theme/dark_plus.json | 4 +- .../main/assets/editor/theme/light_plus.json | 6 +- .../model/editor/EditorColors.java | 12 ++- .../ui/edit/editor/CodeEditText.java | 73 ++++++++++++++----- .../ui/edit/editor/CodeEditor.java | 22 +----- .../ui/edit/editor/LayoutHelper.java | 20 +++++ .../scriptdroid/ui/edit/theme/Theme.java | 6 ++ 7 files changed, 101 insertions(+), 42 deletions(-) diff --git a/app/src/main/assets/editor/theme/dark_plus.json b/app/src/main/assets/editor/theme/dark_plus.json index 6ad962b9..554b658f 100644 --- a/app/src/main/assets/editor/theme/dark_plus.json +++ b/app/src/main/assets/editor/theme/dark_plus.json @@ -4,10 +4,10 @@ "colors": { "editor.background": "#1E1E1E", "editor.foreground": "#D4D4D4", - "lineNumber.foreground": "#404040", + "editorLineNumber.foreground": "#404040", "imeBar.background": "#dd1e1e1e", "imeBar.foreground": "#f1f1f1", - "editor.selectionHighlightBackground": "#ADD6FF26" + "editor.lineHighlightBackground": "#2e2e35" }, "tokenColors": [ { diff --git a/app/src/main/assets/editor/theme/light_plus.json b/app/src/main/assets/editor/theme/light_plus.json index 86554ba1..ab3ac9eb 100644 --- a/app/src/main/assets/editor/theme/light_plus.json +++ b/app/src/main/assets/editor/theme/light_plus.json @@ -483,9 +483,11 @@ "colors": { "imeBar.background": "#ddf0f1f2", "imeBar.foreground": "#222327", - "lineNumber.foreground": "#9DA39A", + "editorLineNumber.foreground": "#9DA39A", "editor.background": "#F5F5F5", "editor.foreground": "#000000", + "editor.lineHighlightBackground": "#E4F6D4", + "focusBorder": "#A6B39B", "pickerGroup.foreground": "#A6B39B", "pickerGroup.border": "#749351", @@ -497,12 +499,10 @@ "list.highlightForeground": "#9769dc", "selection.background": "#C9D0D9", "editorWhitespace.foreground": "#AAAAAA", - "editor.lineHighlightBackground": "#E4F6D4", "editor.selectionBackground": "#C9D0D9", "panel.background": "#F5F5F5", "sideBar.background": "#F2F2F2", "sideBarSectionHeader.background": "#ede8ef", - "editorLineNumber.foreground": "#9DA39A", "editorCursor.foreground": "#54494B", "inputOption.activeBorder": "#adafb7", "dropdown.background": "#F5F5F5", diff --git a/app/src/main/java/com/stardust/scriptdroid/model/editor/EditorColors.java b/app/src/main/java/com/stardust/scriptdroid/model/editor/EditorColors.java index 8f8a66bc..10932a05 100644 --- a/app/src/main/java/com/stardust/scriptdroid/model/editor/EditorColors.java +++ b/app/src/main/java/com/stardust/scriptdroid/model/editor/EditorColors.java @@ -12,7 +12,7 @@ public class EditorColors { private String mEditorForeground; @SerializedName("editor.inactiveSelectionBackground") private String mEditorInactiveSelectionBackground; - @SerializedName("lineNumber.foreground") + @SerializedName("editorLineNumber.foreground") private String mLineNumberForeground; @SerializedName("editor.selectionHighlightBackground") private String mEditorSelectionHighlightBackground; @@ -20,6 +20,16 @@ public class EditorColors { private String mImeBackgroundColor; @SerializedName("imeBar.foreground") private String mImeForegroundColor; + @SerializedName("editor.lineHighlightBackground") + private String mLineHighlightBackground; + + public String getLineHighlightBackground() { + return mLineHighlightBackground; + } + + public void setLineHighlightBackground(String lineHighlightBackground) { + mLineHighlightBackground = lineHighlightBackground; + } public String getEditorBackground() { return mEditorBackground; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditText.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditText.java index 8e653b3b..b97906aa 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditText.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditText.java @@ -24,7 +24,6 @@ import android.graphics.Paint; import android.graphics.Typeface; import android.support.v7.widget.AppCompatEditText; import android.text.Layout; -import android.text.method.ScrollingMovementMethod; import android.util.AttributeSet; import android.util.Log; import android.util.TimingLogger; @@ -50,6 +49,8 @@ public class CodeEditText extends AppCompatEditText { private volatile JavaScriptHighlighter.HighlightTokens mHighlightTokens; private Theme mTheme; private TimingLogger mLogger = new TimingLogger(LOG_TAG, "draw"); + private Paint mLineHighlightPaint = new Paint(); + private int mFirstLineForDraw = -1, mLastLineForDraw; public CodeEditText(Context context) { super(context); @@ -71,6 +72,7 @@ public class CodeEditText extends AppCompatEditText { setTypeface(Typeface.MONOSPACE); setHorizontallyScrolling(true); mTheme = Theme.getDefault(getContext()); + mLineHighlightPaint.setStyle(Paint.Style.FILL); } public void setTheme(Theme theme) { @@ -84,39 +86,57 @@ public class CodeEditText extends AppCompatEditText { if (mParentScrollView == null) { mParentScrollView = (HVScrollView) getParent(); } + updatePaddingForGutter(); + updateLineRangeForDraw(canvas); + + //绘制当前行高亮需要在绘制光标之前 + drawLineHighlight(canvas, mLineHighlightPaint, getCurrentLine()); + + //调用super.onDraw绘制光标和选择高亮。因为字体颜色被设置为透明因此super.onDraw()绘制的字体不显示 + // TODO: 2018/2/24 优化效率。不绘制透明字体。 + super.onDraw(canvas); + mLogger.addSplit("super draw"); + + canvas.save(); + canvas.translate(0, getExtendedPaddingTop()); + drawText(canvas); + mLogger.addSplit("draw text"); + canvas.restore(); + + mLogger.dumpToLog(); + } + + private void updateLineRangeForDraw(Canvas canvas) { + Layout layout = getLayout(); + if (layout == null) + return; + long lineRange = getLineRangeForDraw(layout, canvas); + mFirstLineForDraw = LayoutHelper.unpackRangeStartFromLong(lineRange); + mLastLineForDraw = LayoutHelper.unpackRangeEndFromLong(lineRange); + } + + private void updatePaddingForGutter() { // 根据行号计算左边距padding 留出绘制行号的空间 String max = Integer.toString(getLineCount()); float gutterWidth = getPaint().measureText(max) + 20; if (getPaddingLeft() != gutterWidth) { setPadding((int) gutterWidth, 0, 0, 0); } - super.onDraw(canvas); - mLogger.addSplit("super draw"); - // 画文字 - canvas.save(); - canvas.translate(0, getExtendedPaddingTop()); - drawText(canvas); - mLogger.addSplit("draw text"); - canvas.restore(); - mLogger.dumpToLog(); } // 绘制文本着色 private void drawText(Canvas canvas) { - JavaScriptHighlighter.HighlightTokens highlightTokens = mHighlightTokens; - Layout layout = getLayout(); - long lineRange = getLineRangeForDraw(layout, canvas); - int firstLineForDraw = LayoutHelper.unpackRangeStartFromLong(lineRange); - int lastLineForDraw = LayoutHelper.unpackRangeEndFromLong(lineRange); - if (firstLineForDraw < 0) { + if (mFirstLineForDraw < 0) { return; } + JavaScriptHighlighter.HighlightTokens highlightTokens = mHighlightTokens; + Layout layout = getLayout(); int lineCount = getLineCount(); int paddingLeft = getPaddingLeft(); Paint paint = getPaint(); if (DEBUG) - Log.d(LOG_TAG, "draw line: " + (lastLineForDraw - firstLineForDraw + 1)); - for (int line = firstLineForDraw; line <= lastLineForDraw && line < lineCount; line++) { + Log.d(LOG_TAG, "draw line: " + (mLastLineForDraw - mFirstLineForDraw + 1)); + for (int line = mFirstLineForDraw; line <= mLastLineForDraw && line < lineCount; line++) { int lineBottom = layout.getLineTop(line + 1); int lineBaseline = lineBottom - layout.getLineDescent(line); @@ -128,6 +148,23 @@ public class CodeEditText extends AppCompatEditText { } } + private void drawLineHighlight(Canvas canvas, Paint paint, int line) { + if (line < mFirstLineForDraw || line > mLastLineForDraw || mFirstLineForDraw < 0 || line < 0) { + return; + } + int lineTop = getLayout().getLineTop(line); + int lineBottom = getLayout().getLineTop(line + 1); + paint.setColor(mTheme.getLineHighlightBackgroundColor()); + canvas.drawRect(0, lineTop, canvas.getWidth(), lineBottom, paint); + } + + private int getCurrentLine() { + Layout layout = getLayout(); + if (layout == null) + return -1; + return LayoutHelper.getLineOfChar(getLayout(), getSelectionStart()); + } + private void drawCode(Canvas canvas, Paint paint, int paddingLeft, int line, Layout layout, int lineBaseline, JavaScriptHighlighter.HighlightTokens highlightTokens) { int lineStart = layout.getLineStart(line); if (lineStart >= mHighlightTokens.getText().length()) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java index f0962f2d..f807be42 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/CodeEditor.java @@ -80,7 +80,7 @@ public class CodeEditor extends HVScrollView { } public void copyLine() { - int line = getLineOfChar(mCodeEditText.getSelectionStart()); + int line = LayoutHelper.getLineOfChar(mCodeEditText.getLayout(), mCodeEditText.getSelectionStart()); if (line < 0 || line >= mCodeEditText.getLayout().getLineCount()) return; CharSequence lineText = mCodeEditText.getText().subSequence(mCodeEditText.getLayout().getLineStart(line), @@ -89,23 +89,9 @@ public class CodeEditor extends HVScrollView { Snackbar.make(this, R.string.text_already_copy_to_clip, Snackbar.LENGTH_SHORT).show(); } - private int getLineOfChar(int i) { - int low = 0; - int high = mCodeEditText.getLineCount() - 1; - while (low < high) { - int mid = (low + high) >>> 1; - int midVal = mCodeEditText.getLayout().getLineEnd(mid); - - if (midVal <= i) - low = mid + 1; - else if (midVal > i) - high = mid - 1; - } - return low; - } public void deleteLine() { - int line = getLineOfChar(mCodeEditText.getSelectionStart()); + int line = LayoutHelper.getLineOfChar(mCodeEditText.getLayout(), mCodeEditText.getSelectionStart()); if (line < 0 || line >= mCodeEditText.getLayout().getLineCount()) return; mCodeEditText.getText().replace(mCodeEditText.getLayout().getLineStart(line), @@ -121,14 +107,14 @@ public class CodeEditor extends HVScrollView { } public void jumpToLineStart() { - int line = getLineOfChar(mCodeEditText.getSelectionStart()); + int line = LayoutHelper.getLineOfChar(mCodeEditText.getLayout(), mCodeEditText.getSelectionStart()); if (line < 0 || line >= mCodeEditText.getLayout().getLineCount()) return; mCodeEditText.setSelection(mCodeEditText.getLayout().getLineStart(line)); } public void jumpToLineEnd() { - int line = getLineOfChar(mCodeEditText.getSelectionStart()); + int line = LayoutHelper.getLineOfChar(mCodeEditText.getLayout(), mCodeEditText.getSelectionStart()); if (line < 0 || line >= mCodeEditText.getLayout().getLineCount()) return; mCodeEditText.setSelection(mCodeEditText.getLayout().getLineEnd(line) - 1); diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/LayoutHelper.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/LayoutHelper.java index 8c4d3f76..ba7cda56 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/LayoutHelper.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/LayoutHelper.java @@ -1,5 +1,6 @@ package com.stardust.scriptdroid.ui.edit.editor; +import android.content.pm.PackageManager; import android.graphics.Canvas; import android.graphics.Rect; import android.text.Layout; @@ -51,4 +52,23 @@ public class LayoutHelper { return (int) (range & 0x00000000FFFFFFFFL); } + + public static int getLineOfChar(Layout layout, int charIndex) { + int low = 0; + int high = layout.getLineCount() - 1; + while (low < high) { + int mid = (low + high) >>> 1; + int midVal = layout.getLineEnd(mid); + + if (charIndex > midVal) { + low = mid + 1; + } else if (charIndex < midVal) { + high = mid; + } else { + return Math.min(layout.getLineCount() - 1, mid + 1); + } + } + return low; + } + } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/theme/Theme.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/theme/Theme.java index a8a110f5..156bfe28 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/theme/Theme.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/theme/Theme.java @@ -24,6 +24,7 @@ public class Theme { private int mImeBarBackgroundColor = 0xDDFFFFFF; private int mImeBarForegroundColor = Color.WHITE; private EditorTheme mEditorTheme; + private int mLineHighlightBackground; public Theme(EditorTheme theme) { mEditorTheme = theme; @@ -32,6 +33,7 @@ public class Theme { mLineNumberColor = parseColor(theme.getEditorColors().getLineNumberForeground(), mLineNumberColor); mImeBarBackgroundColor = parseColor(theme.getEditorColors().getImeBackgroundColor(), mImeBarBackgroundColor); mImeBarForegroundColor = parseColor(theme.getEditorColors().getImeForegroundColor(), mImeBarForegroundColor); + mLineHighlightBackground = parseColor(theme.getEditorColors().getLineHighlightBackground(), mLineHighlightBackground); for (TokenColor tokenColor : theme.getTokenColors()) { String foregroundStr = tokenColor.getSettings().getForeground(); @@ -120,6 +122,10 @@ public class Theme { mImeBarForegroundColor = imeBarForegroundColor; } + public int getLineHighlightBackgroundColor() { + return mLineHighlightBackground; + } + @Override public boolean equals(Object o) { if (this == o) return true;