From 9dd5932f0a14fb519d3e923faa64e39f4ee00b17 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Wed, 6 Nov 2024 21:30:29 +0800 Subject: [PATCH 1/8] enhance line numbers --- .../activity/DocumentEditAndViewFragment.java | 45 ++- .../frontend/textview/HighlightingEditor.java | 195 +---------- .../textview/LineNumbersTextView.java | 302 ++++++++++++++++++ .../res/layout/document__fragment__edit.xml | 47 ++- .../layout/document__fragment__share_into.xml | 1 - 5 files changed, 366 insertions(+), 224 deletions(-) create mode 100644 app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 39f02c6fbd..c08faa08e9 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -33,6 +33,7 @@ import android.webkit.JavascriptInterface; import android.webkit.WebSettings; import android.webkit.WebView; +import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.SearchView; import android.widget.Toast; @@ -51,6 +52,7 @@ import net.gsantner.markor.frontend.MarkorDialogFactory; import net.gsantner.markor.frontend.filebrowser.MarkorFileBrowserFactory; import net.gsantner.markor.frontend.textview.HighlightingEditor; +import net.gsantner.markor.frontend.textview.LineNumbersTextView; import net.gsantner.markor.frontend.textview.TextViewUtils; import net.gsantner.markor.model.AppSettings; import net.gsantner.markor.model.Document; @@ -91,10 +93,12 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do private HighlightingEditor _hlEditor; private WebView _webView; private MarkorWebViewClient _webViewClient; + private FrameLayout _editorHolder; private ViewGroup _textActionsBar; private DraggableScrollbarScrollView _primaryScrollView; private HorizontalScrollView _hsView; + private LineNumbersTextView _lineNumbersView; private SearchView _menuSearchViewForViewMode; private Document _document; private FormatRegistry _format; @@ -103,6 +107,7 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do private MenuItem _saveMenuItem, _undoMenuItem, _redoMenuItem; private boolean _isPreviewVisible; private boolean _nextConvertToPrintMode = false; + private long _lineNumbersRefreshTime; // Line numbers refresh time on scroll changed public DocumentEditAndViewFragment() { @@ -132,9 +137,23 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { final Activity activity = getActivity(); _hlEditor = view.findViewById(R.id.document__fragment__edit__highlighting_editor); + _editorHolder = view.findViewById(R.id.document__fragment__edit__editor_holder); _textActionsBar = view.findViewById(R.id.document__fragment__edit__text_actions_bar); _webView = view.findViewById(R.id.document__fragment_view_webview); _primaryScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent); + _primaryScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> + { + if (_lineNumbersView.isLineNumbersEnabled()) { + final long time = System.currentTimeMillis(); + if (time - _lineNumbersRefreshTime > 125) { + _lineNumbersRefreshTime = time; + _lineNumbersView.forceRefresh(); + } + } + }); + _lineNumbersView = view.findViewById(R.id.document__fragment__edit__line_numbers_view); + _lineNumbersView.setEditText(_hlEditor); + _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); _cu = new MarkorContextUtils(activity); // Using `if (_document != null)` everywhere is dangerous @@ -202,7 +221,6 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { _hlEditor.setTextColor(_appSettings.getEditorForegroundColor()); _hlEditor.setGravity(_appSettings.isEditorStartEditingInCenter() ? Gravity.CENTER : Gravity.NO_GRAVITY); _hlEditor.setHighlightingEnabled(_appSettings.getDocumentHighlightState(_document.path, _hlEditor.getText())); - _hlEditor.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); _hlEditor.setAutoFormatEnabled(_appSettings.getDocumentAutoFormatEnabled(_document.path)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Do not need to send contents to accessibility @@ -286,7 +304,7 @@ public void onPause() { _appSettings.setDocumentPreviewState(_document.path, _isPreviewVisible); _appSettings.setLastEditPosition(_document.path, TextViewUtils.getSelection(_hlEditor)[0]); - if(_document.path.equals(_appSettings.getTodoFile().getAbsolutePath())){ + if (_document.path.equals(_appSettings.getTodoFile().getAbsolutePath())) { TodoWidgetProvider.updateTodoWidgets(); } super.onPause(); @@ -522,7 +540,7 @@ public boolean onOptionsItemSelected(@NonNull final MenuItem item) { if (saveDocument(false)) { TextConverterBase converter = FormatRegistry.getFormat(_document.getFormat(), activity, _document).getConverter(); _cu.shareText(getActivity(), - converter.convertMarkup(getTextString(), getActivity(), false, _hlEditor.isLineNumbersEnabled(), _document.file), + converter.convertMarkup(getTextString(), getActivity(), false, _lineNumbersView.isLineNumbersEnabled(), _document.file), "text/" + (item.getItemId() == R.id.action_share_html ? "html" : "plain") ); } @@ -611,9 +629,9 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { return true; } case R.id.action_line_numbers: { - final boolean newState = !_hlEditor.isLineNumbersEnabled(); + final boolean newState = !_lineNumbersView.isLineNumbersEnabled(); _appSettings.setDocumentLineNumbersEnabled(_document.path, newState); - _hlEditor.setLineNumbersEnabled(newState); + _lineNumbersView.setLineNumbersEnabled(newState); updateMenuToggleStates(0); return true; } @@ -742,7 +760,7 @@ private void updateMenuToggleStates(final int selectedFormatActionId) { mi.setChecked(_hlEditor.getHighlightingEnabled()); } if ((mi = _fragmentMenu.findItem(R.id.action_line_numbers)) != null) { - mi.setChecked(_hlEditor.isLineNumbersEnabled()); + mi.setChecked(_lineNumbersView.isLineNumbersEnabled()); } if ((mi = _fragmentMenu.findItem(R.id.action_enable_auto_format)) != null) { mi.setChecked(_hlEditor.getAutoFormatEnabled()); @@ -760,19 +778,17 @@ private void updateMenuToggleStates(final int selectedFormatActionId) { } private boolean isWrapped() { - return _hsView == null || (_hlEditor.getParent() == _primaryScrollView); + return _hsView == null || (_hlEditor.getParent() == _editorHolder); } private void setHorizontalScrollMode(final boolean wrap) { final Context context = getContext(); if (context != null && _hlEditor != null && isWrapped() != wrap) { - final int[] sel = TextViewUtils.getSelection(_hlEditor); - final boolean hlEnabled = _hlEditor.getHighlightingEnabled(); _hlEditor.setHighlightingEnabled(false); - _primaryScrollView.removeAllViews(); + _editorHolder.removeAllViews(); if (_hsView != null) { _hsView.removeAllViews(); } @@ -782,15 +798,14 @@ private void setHorizontalScrollMode(final boolean wrap) { _hsView.setFillViewport(true); } _hsView.addView(_hlEditor); - _primaryScrollView.addView(_hsView); + _editorHolder.addView(_hsView); } else { - _primaryScrollView.addView(_hlEditor); + _editorHolder.addView(_hlEditor); } _hlEditor.setHighlightingEnabled(hlEnabled); - // Run after layout() of immediate parent completes - (wrap ? _primaryScrollView : _hsView).post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel)); + (wrap ? _editorHolder : _hsView).post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel)); } } @@ -862,7 +877,7 @@ private boolean isDisplayedAtMainActivity() { } public void updateViewModeText() { - _format.getConverter().convertMarkupShowInWebView(_document, getTextString(), getActivity(), _webView, _nextConvertToPrintMode, _hlEditor.isLineNumbersEnabled()); + _format.getConverter().convertMarkupShowInWebView(_document, getTextString(), getActivity(), _webView, _nextConvertToPrintMode, _lineNumbersView.isLineNumbersEnabled()); } public void setViewModeVisibility(final boolean show) { diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java index d29063abc4..0f86c492c1 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java @@ -30,10 +30,10 @@ import net.gsantner.markor.ApplicationObject; import net.gsantner.markor.activity.MainActivity; import net.gsantner.markor.model.AppSettings; +import net.gsantner.markor.util.TextCasingUtils; import net.gsantner.opoc.format.GsTextUtils; import net.gsantner.opoc.wrapper.GsCallback; import net.gsantner.opoc.wrapper.GsTextWatcherAdapter; -import net.gsantner.markor.util.TextCasingUtils; import java.util.Objects; import java.util.concurrent.ExecutorService; @@ -65,7 +65,6 @@ public class HighlightingEditor extends AppCompatEditText { private TextWatcher _autoFormatModifier; private boolean _autoFormatEnabled; private boolean _saveInstanceState = true; - private final LineNumbersDrawer _lineNumbersDrawer = new LineNumbersDrawer(this); private final ExecutorService executor = new ThreadPoolExecutor(0, 3, 60, TimeUnit.SECONDS, new SynchronousQueue<>()); private final AtomicBoolean _textUnchangedWhileHighlighting = new AtomicBoolean(true); @@ -115,17 +114,12 @@ public void afterTextChanged(final Editable s) { @Override public boolean onPreDraw() { - _lineNumbersDrawer.setTextSize(getTextSize()); return super.onPreDraw(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - - if (_numEnabled) { - _lineNumbersDrawer.draw(canvas); - } } // Highlighting @@ -253,23 +247,6 @@ public boolean setHighlightingEnabled(final boolean enable) { return prev; } - public boolean isLineNumbersEnabled() { - return _numEnabled; - } - - public void setLineNumbersEnabled(final boolean enable) { - if (enable ^ _numEnabled) { - post(this::invalidate); - } - _numEnabled = enable; - if (_numEnabled) { - _lineNumbersDrawer.startLineTracking(); - } else { - _lineNumbersDrawer.reset(); - _lineNumbersDrawer.stopLineTracking(); - } - } - // Region to highlight private int[] hlRegion() { if (_isDynamicHighlightingEnabled) { @@ -553,174 +530,4 @@ public int moveCursorToBeginOfLine(int offset) { public boolean indexesValid(int... indexes) { return GsTextUtils.inRange(0, length(), indexes); } - - static class LineNumbersDrawer { - - private final AppCompatEditText _editor; - private final Paint _paint = new Paint(); - - private final int _defaultPaddingLeft; - private static final int LINE_NUMBER_PADDING_LEFT = 18; - private static final int LINE_NUMBER_PADDING_RIGHT = 12; - - private final Rect _visibleArea = new Rect(); - private final Rect _lineNumbersArea = new Rect(); - - private int _numberX; - private int _gutterX; - private int _maxNumber = 1; // to gauge gutter width - private int _maxNumberDigits; - private float _oldTextSize; - private final int[] _startLine = {0, 1}; // {line index, actual line number} - - private final GsTextWatcherAdapter _lineTrackingWatcher = new GsTextWatcherAdapter() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - _maxNumber -= GsTextUtils.countChar(s, start, start + count, '\n'); - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - _maxNumber += GsTextUtils.countChar(s, start, start + count, '\n'); - } - }; - - public LineNumbersDrawer(final AppCompatEditText editor) { - _editor = editor; - _paint.setColor(0xFF999999); - _paint.setTextAlign(Paint.Align.RIGHT); - _defaultPaddingLeft = editor.getPaddingLeft(); - } - - public void setTextSize(final float textSize) { - _paint.setTextSize(textSize); - } - - public boolean isTextSizeChanged() { - if (_paint.getTextSize() == _oldTextSize) { - return false; - } else { - _oldTextSize = _paint.getTextSize(); - return true; - } - } - - public boolean isMaxNumberDigitsChanged() { - final int oldDigits = _maxNumberDigits; - - if (_maxNumber < 10) { - _maxNumberDigits = 1; - } else if (_maxNumber < 100) { - _maxNumberDigits = 2; - } else if (_maxNumber < 1000) { - _maxNumberDigits = 3; - } else if (_maxNumber < 10000) { - _maxNumberDigits = 4; - } else { - _maxNumberDigits = 5; - } - return _maxNumberDigits != oldDigits; - } - - public boolean isOutOfLineNumbersArea() { - final int margin = (int) (_visibleArea.height() * 0.5f); - final int top = _visibleArea.top - margin; - final int bottom = _visibleArea.bottom + margin; - - if (top < _lineNumbersArea.top || bottom > _lineNumbersArea.bottom) { - // Reset line numbers area - // height of line numbers area = (1.5 + 1 + 1.5) * height of visible area - _lineNumbersArea.top = top - _visibleArea.height(); - _lineNumbersArea.bottom = bottom + _visibleArea.height(); - return true; - } else { - return false; - } - } - - public void startLineTracking() { - _editor.removeTextChangedListener(_lineTrackingWatcher); - _maxNumber = 1; - final CharSequence text = _editor.getText(); - if (text != null) { - _maxNumber += GsTextUtils.countChar(text, 0, text.length(), '\n'); - } - _editor.addTextChangedListener(_lineTrackingWatcher); - } - - public void stopLineTracking() { - _editor.removeTextChangedListener(_lineTrackingWatcher); - } - - /** - * Draw line numbers. - * - * @param canvas The canvas on which the line numbers will be drawn. - */ - public void draw(final Canvas canvas) { - if (!_editor.getLocalVisibleRect(_visibleArea)) { - return; - } - - final CharSequence text = _editor.getText(); - final Layout layout = _editor.getLayout(); - if (text == null || layout == null) { - return; - } - - // If text size or the max line number of digits changed, - // update the variables and reset padding - if (isTextSizeChanged() || isMaxNumberDigitsChanged()) { - _numberX = LINE_NUMBER_PADDING_LEFT + (int) _paint.measureText(String.valueOf(_maxNumber)); - _gutterX = _numberX + LINE_NUMBER_PADDING_RIGHT; - _editor.setPadding(_gutterX + 12, _editor.getPaddingTop(), _editor.getPaddingRight(), _editor.getPaddingBottom()); - } - - int i = _startLine[0], number = _startLine[1]; - // If current visible area is out of current line numbers area, - // iterate from the first line to recalculate the start line - if (isOutOfLineNumbersArea()) { - i = 0; - number = 1; - _startLine[0] = -1; - } - - // Draw border of the gutter - canvas.drawLine(_gutterX, _lineNumbersArea.top, _gutterX, _lineNumbersArea.bottom, _paint); - - // Draw line numbers - final int count = layout.getLineCount(); - final int offsetY = _editor.getPaddingTop(); - for (; i < count; i++) { - int start; - try { - start = layout.getLineStart(i); - } catch (IndexOutOfBoundsException ex) { - break; // Even though the drawing is against count, might throw IndexOutOfBounds during drawing - } - if (start == 0 || text.charAt(start - 1) == '\n') { - final int y = layout.getLineBaseline(i); - if (y > _lineNumbersArea.bottom) { - break; - } - if (y > _lineNumbersArea.top) { - if (_startLine[0] < 0) { - _startLine[0] = i; - _startLine[1] = number; - } - canvas.drawText(String.valueOf(number), _numberX, y + offsetY, _paint); - } - number++; - } - } - } - - /** - * Reset to the state without line numbers. - */ - public void reset() { - _editor.setPadding(_defaultPaddingLeft, _editor.getPaddingTop(), _editor.getPaddingRight(), _editor.getPaddingBottom()); - _maxNumberDigits = 0; - } - } } \ No newline at end of file diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java new file mode 100644 index 0000000000..947c8744a7 --- /dev/null +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -0,0 +1,302 @@ +package net.gsantner.markor.frontend.textview; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.Editable; +import android.text.Layout; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.widget.EditText; + +import androidx.appcompat.widget.AppCompatTextView; + +/** + * @author Li Guanglin + */ +public class LineNumbersTextView extends AppCompatTextView { + private boolean lineNumbersEnabled; + private LineNumbersDrawer lineNumbersDrawer; + + public LineNumbersTextView(Context context) { + super(context); + } + + public LineNumbersTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LineNumbersTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (lineNumbersEnabled) { + lineNumbersDrawer.draw(canvas); + } + } + + public void forceRefresh() { + setText(""); // Use setText("") to activate LineNumbersTextView refresh + } + + public void setEditText(final EditText editText) { + lineNumbersDrawer = new LineNumbersDrawer(editText, this); + } + + public void setLineNumbersEnabled(final boolean enabled) { + lineNumbersEnabled = enabled; + if (lineNumbersEnabled) { + lineNumbersDrawer.prepare(); + } else { + lineNumbersDrawer.reset(); + } + forceRefresh(); + } + + public boolean isLineNumbersEnabled() { + return lineNumbersEnabled; + } + + static class LineNumbersDrawer { + public final EditText editText; + public final LineNumbersTextView textView; + + private final Paint paint = new Paint(); + + private static final int NUMBER_PADDING_LEFT = 18; + private static final int NUMBER_PADDING_RIGHT = 14; + private static final int PADDING_LEFT_NUMBERS_ENABLED = 10; + private final int paddingLeft; + + private final Rect visibleArea = new Rect(); + private final Rect lineNumbersArea = new Rect(); + + private int fenceX; + private int numberX; + private int maxNumber = 1; // To gauge the width of line numbers fence + private int maxNumberDigits; + private int lastMaxNumber; + private int lastLayoutLineCount; + private float lastTextSize; + + private final int[] startLine = {0, 1}; // {line index, actual line number} + + private final TextWatcher lineTrackingWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + maxNumber -= countLines(s, start, start + count); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + maxNumber += countLines(s, start, start + count); + } + + @Override + public void afterTextChanged(Editable editable) { + if (isLayoutLineCountChanged() || isMaxNumberChanged()) { + textView.forceRefresh(); + } + } + }; + + public LineNumbersDrawer(final EditText editText, final LineNumbersTextView textView) { + this.editText = editText; + this.textView = textView; + this.paddingLeft = editText.getPaddingLeft(); + paint.setColor(0xFF999999); + paint.setTextAlign(Paint.Align.RIGHT); + } + + private boolean isOutOfLineNumbersArea() { + final int margin = (int) (visibleArea.height() * 0.5f); + final int top = visibleArea.top - margin; + final int bottom = visibleArea.bottom + margin; + + if (top < lineNumbersArea.top || bottom > lineNumbersArea.bottom) { + // Set line numbers area + // height of line numbers area = (1.5 + 1 + 1.5) * height of visible area + lineNumbersArea.top = top - visibleArea.height(); + lineNumbersArea.bottom = bottom + visibleArea.height(); + return true; + } else { + return false; + } + } + + private boolean isTextSizeChanged() { + if (editText.getTextSize() == lastTextSize) { + return false; + } else { + lastTextSize = editText.getTextSize(); + paint.setTextSize(lastTextSize); + return true; + } + } + + private boolean isMaxNumberChanged() { + if (maxNumber == lastMaxNumber) { + return false; + } else { + lastMaxNumber = maxNumber; + return true; + } + } + + private boolean isMaxNumberDigitsChanged() { + int digits; + if (maxNumber < 10) { + digits = 1; + } else if (maxNumber < 100) { + digits = 2; + } else if (maxNumber < 1000) { + digits = 3; + } else if (maxNumber < 10000) { + digits = 4; + } else { + digits = 5; + } + + if (digits == maxNumberDigits) { + return false; + } + + maxNumberDigits = digits; + return true; + } + + private boolean isLayoutLineCountChanged() { + final Layout layout = editText.getLayout(); + if (layout == null) { + return true; + } + + final int lineCount = layout.getLineCount(); + if (lineCount == lastLayoutLineCount) { + return false; + } else { + lastLayoutLineCount = lineCount; + return true; + } + } + + private int countLines(final CharSequence s, int start, int end) { + int count = 0; + for (; start < end; start++) { + if (s.charAt(start) == '\n') { + count++; + } + } + return count; + } + + private void lineTracking(boolean enabled) { + editText.removeTextChangedListener(lineTrackingWatcher); + + if (enabled) { + maxNumber = 1; + final CharSequence text = editText.getText(); + if (text != null) { + maxNumber += countLines(text, 0, text.length()); + } + editText.addTextChangedListener(lineTrackingWatcher); + } + } + + /** + * Prepare for drawing line numbers. + */ + public void prepare() { + lineTracking(true); + textView.setVisibility(VISIBLE); + editText.setPadding(PADDING_LEFT_NUMBERS_ENABLED, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); + } + + /** + * Draw line numbers. + * + * @param canvas The canvas on which the line numbers will be drawn. + */ + public void draw(final Canvas canvas) { + if (!editText.getLocalVisibleRect(visibleArea)) { + return; + } + + final CharSequence text = editText.getText(); + final Layout layout = editText.getLayout(); + if (text == null || layout == null) { + return; + } + + // If text size or the max line number of digits changed, update related variables + if (isTextSizeChanged() || isMaxNumberDigitsChanged()) { + numberX = NUMBER_PADDING_LEFT + (int) paint.measureText(String.valueOf(maxNumber)); + fenceX = numberX + NUMBER_PADDING_RIGHT; + textView.setWidth(fenceX + 1); + } + + // If current visible area is out of current line numbers area, + // will recalculate the start line + boolean invalid = false; + if (isOutOfLineNumbersArea()) { + invalid = true; + startLine[0] = 0; + startLine[1] = 1; + } + + // Draw right border of the fence + canvas.drawLine(fenceX, lineNumbersArea.top, fenceX, lineNumbersArea.bottom, paint); + + // Draw line numbers + int i = startLine[0]; + int number = startLine[1]; + int y = layout.getLineBaseline(i); + final int count = layout.getLineCount(); + final int offsetY = editText.getPaddingTop(); + + if (y > lineNumbersArea.top) { + if (invalid) { + invalid = false; + startLine[0] = i; + startLine[1] = number; + } + canvas.drawText(String.valueOf(number), numberX, layout.getLineBaseline(i) + offsetY, paint); + } + i++; + number++; + + for (; i < count; i++) { + if (text.charAt(layout.getLineStart(i) - 1) == '\n') { + y = layout.getLineBaseline(i); + if (y > lineNumbersArea.top) { + if (invalid) { + invalid = false; + startLine[0] = i; + startLine[1] = number; + } + canvas.drawText(String.valueOf(number), numberX, y + offsetY, paint); + if (y > lineNumbersArea.bottom) { + break; + } + } + number++; + } + } + } + + /** + * Reset states related line numbers. + */ + public void reset() { + lineTracking(false); + maxNumberDigits = 0; + textView.setWidth(0); + textView.setVisibility(GONE); + editText.setPadding(paddingLeft, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); + } + } +} diff --git a/app/src/main/res/layout/document__fragment__edit.xml b/app/src/main/res/layout/document__fragment__edit.xml index 7bd95f3cea..a947f1e6ed 100644 --- a/app/src/main/res/layout/document__fragment__edit.xml +++ b/app/src/main/res/layout/document__fragment__edit.xml @@ -26,21 +26,40 @@ android:background="@android:color/transparent" android:fillViewport="true"> - + android:layout_height="match_parent" + android:orientation="horizontal"> + + + + + + + + - Date: Thu, 7 Nov 2024 13:20:10 +0800 Subject: [PATCH 2/8] tweak padding left for line numbers --- .../gsantner/markor/frontend/textview/LineNumbersTextView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index 947c8744a7..19a80cc90f 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -67,7 +67,7 @@ static class LineNumbersDrawer { private final Paint paint = new Paint(); - private static final int NUMBER_PADDING_LEFT = 18; + private static final int NUMBER_PADDING_LEFT = 16; private static final int NUMBER_PADDING_RIGHT = 14; private static final int PADDING_LEFT_NUMBERS_ENABLED = 10; private final int paddingLeft; From de94df1cd23340f4e6e0b3622aa3f09c48011e08 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Fri, 8 Nov 2024 11:40:39 +0800 Subject: [PATCH 3/8] tweak padding left --- .../markor/frontend/textview/LineNumbersTextView.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index 19a80cc90f..c81839eb69 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -69,8 +69,8 @@ static class LineNumbersDrawer { private static final int NUMBER_PADDING_LEFT = 16; private static final int NUMBER_PADDING_RIGHT = 14; - private static final int PADDING_LEFT_NUMBERS_ENABLED = 10; - private final int paddingLeft; + private static final int EDITOR_PADDING_LEFT = 8; + private final int ORIGINAL_PADDING_LEFT; private final Rect visibleArea = new Rect(); private final Rect lineNumbersArea = new Rect(); @@ -107,7 +107,7 @@ public void afterTextChanged(Editable editable) { public LineNumbersDrawer(final EditText editText, final LineNumbersTextView textView) { this.editText = editText; this.textView = textView; - this.paddingLeft = editText.getPaddingLeft(); + ORIGINAL_PADDING_LEFT = editText.getPaddingLeft(); paint.setColor(0xFF999999); paint.setTextAlign(Paint.Align.RIGHT); } @@ -213,7 +213,7 @@ private void lineTracking(boolean enabled) { public void prepare() { lineTracking(true); textView.setVisibility(VISIBLE); - editText.setPadding(PADDING_LEFT_NUMBERS_ENABLED, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); + editText.setPadding(EDITOR_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } /** @@ -296,7 +296,7 @@ public void reset() { maxNumberDigits = 0; textView.setWidth(0); textView.setVisibility(GONE); - editText.setPadding(paddingLeft, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); + editText.setPadding(ORIGINAL_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } } } From e19c52c242f2f0bd582095805a1be59b5c807b68 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Sun, 10 Nov 2024 15:50:14 +0800 Subject: [PATCH 4/8] resolve the issues mentioned --- .../activity/DocumentEditAndViewFragment.java | 17 ++--- .../frontend/textview/HighlightingEditor.java | 6 +- .../textview/LineNumbersTextView.java | 70 ++++++++++++++----- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index c08faa08e9..eeb711a660 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -107,7 +107,6 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do private MenuItem _saveMenuItem, _undoMenuItem, _redoMenuItem; private boolean _isPreviewVisible; private boolean _nextConvertToPrintMode = false; - private long _lineNumbersRefreshTime; // Line numbers refresh time on scroll changed public DocumentEditAndViewFragment() { @@ -141,19 +140,8 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { _textActionsBar = view.findViewById(R.id.document__fragment__edit__text_actions_bar); _webView = view.findViewById(R.id.document__fragment_view_webview); _primaryScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent); - _primaryScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> - { - if (_lineNumbersView.isLineNumbersEnabled()) { - final long time = System.currentTimeMillis(); - if (time - _lineNumbersRefreshTime > 125) { - _lineNumbersRefreshTime = time; - _lineNumbersView.forceRefresh(); - } - } - }); _lineNumbersView = view.findViewById(R.id.document__fragment__edit__line_numbers_view); - _lineNumbersView.setEditText(_hlEditor); - _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); + _cu = new MarkorContextUtils(activity); // Using `if (_document != null)` everywhere is dangerous @@ -267,6 +255,9 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { } }); } + + _lineNumbersView.setup(_hlEditor, _primaryScrollView); + _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); } @Override diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java index 0f86c492c1..39a452ecfa 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java @@ -57,7 +57,6 @@ public class HighlightingEditor extends AppCompatEditText { private boolean _isDynamicHighlightingEnabled = true; private Runnable _hlDebounced; // Debounced runnable which recomputes highlighting private boolean _hlEnabled; // Whether highlighting is enabled - private boolean _numEnabled; // Whether show line numbers is enabled private final Rect _oldHlRect; // Rect highlighting was previously applied to private final Rect _hlRect; // Current rect private int _hlShiftThreshold = -1; // How much to scroll before re-apply highlight @@ -81,7 +80,6 @@ public HighlightingEditor(Context context, AttributeSet attrs) { } _hlEnabled = false; - _numEnabled = false; _oldHlRect = new Rect(); _hlRect = new Rect(); @@ -194,9 +192,7 @@ public void setDynamicHighlightingEnabled(final boolean enable) { recomputeHighlighting(); } - public boolean isDynamicHighlightingEnabled() { - return _isDynamicHighlightingEnabled; - } + // public boolean isDynamicHighlightingEnabled() { return _isDynamicHighlightingEnabled; } public void setHighlighter(final SyntaxHighlighterBase newHighlighter) { if (_hl != null) { diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index c81839eb69..18c9a36a59 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -8,16 +8,30 @@ import android.text.Layout; import android.text.TextWatcher; import android.util.AttributeSet; +import android.view.View; +import android.view.ViewTreeObserver; import android.widget.EditText; +import android.widget.ScrollView; import androidx.appcompat.widget.AppCompatTextView; -/** - * @author Li Guanglin - */ +@SuppressWarnings("UnusedReturnValue") public class LineNumbersTextView extends AppCompatTextView { - private boolean lineNumbersEnabled; private LineNumbersDrawer lineNumbersDrawer; + private boolean lineNumbersEnabled; + private ScrollView scrollView; + private final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { + private long lastTime; + + @Override + public void onScrollChanged() { + final long time = System.currentTimeMillis(); + if (time - lastTime > 125) { + lastTime = time; + refresh(); + } + } + }; public LineNumbersTextView(Context context) { super(context); @@ -31,6 +45,14 @@ public LineNumbersTextView(Context context, AttributeSet attrs, int defStyleAttr super(context, attrs, defStyleAttr); } + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (isLineNumbersEnabled() && visibility == View.VISIBLE) { + refresh(); + } + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -39,11 +61,15 @@ protected void onDraw(Canvas canvas) { } } - public void forceRefresh() { - setText(""); // Use setText("") to activate LineNumbersTextView refresh + public void refresh() { + setText(""); // To activate LineNumbersTextView refresh + if (getWidth() == 0) { + lineNumbersDrawer.getEditText().postInvalidate(); + } } - public void setEditText(final EditText editText) { + public void setup(final EditText editText, ScrollView scrollView) { + this.scrollView = scrollView; lineNumbersDrawer = new LineNumbersDrawer(editText, this); } @@ -51,10 +77,16 @@ public void setLineNumbersEnabled(final boolean enabled) { lineNumbersEnabled = enabled; if (lineNumbersEnabled) { lineNumbersDrawer.prepare(); + if (scrollView != null) { + scrollView.getViewTreeObserver().addOnScrollChangedListener(onScrollChangedListener); + } } else { - lineNumbersDrawer.reset(); + lineNumbersDrawer.done(); + if (scrollView != null) { + scrollView.getViewTreeObserver().removeOnScrollChangedListener(onScrollChangedListener); + } } - forceRefresh(); + refresh(); } public boolean isLineNumbersEnabled() { @@ -62,8 +94,8 @@ public boolean isLineNumbersEnabled() { } static class LineNumbersDrawer { - public final EditText editText; - public final LineNumbersTextView textView; + private final EditText editText; + private final LineNumbersTextView textView; private final Paint paint = new Paint(); @@ -99,7 +131,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { @Override public void afterTextChanged(Editable editable) { if (isLayoutLineCountChanged() || isMaxNumberChanged()) { - textView.forceRefresh(); + textView.refresh(); } } }; @@ -112,6 +144,10 @@ public LineNumbersDrawer(final EditText editText, final LineNumbersTextView text paint.setTextAlign(Paint.Align.RIGHT); } + public EditText getEditText() { + return editText; + } + private boolean isOutOfLineNumbersArea() { final int margin = (int) (visibleArea.height() * 0.5f); final int top = visibleArea.top - margin; @@ -194,7 +230,7 @@ private int countLines(final CharSequence s, int start, int end) { return count; } - private void lineTracking(boolean enabled) { + private void setLineTracking(boolean enabled) { editText.removeTextChangedListener(lineTrackingWatcher); if (enabled) { @@ -211,7 +247,7 @@ private void lineTracking(boolean enabled) { * Prepare for drawing line numbers. */ public void prepare() { - lineTracking(true); + setLineTracking(true); textView.setVisibility(VISIBLE); editText.setPadding(EDITOR_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } @@ -289,10 +325,10 @@ public void draw(final Canvas canvas) { } /** - * Reset states related line numbers. + * Reset some states related line numbers. */ - public void reset() { - lineTracking(false); + public void done() { + setLineTracking(false); maxNumberDigits = 0; textView.setWidth(0); textView.setVisibility(GONE); From 0d381e8a24408199267396b13c34cd95b1b73429 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Sun, 10 Nov 2024 21:00:20 +0800 Subject: [PATCH 5/8] minor improvements --- .../markor/activity/DocumentEditAndViewFragment.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index eeb711a660..8fab9ce722 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -155,6 +155,9 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { return; } + _lineNumbersView.setup(_hlEditor, _primaryScrollView); + _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && _appSettings.getSetWebViewFulldrawing()) { WebView.enableSlowWholeDocumentDraw(); } @@ -255,9 +258,6 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { } }); } - - _lineNumbersView.setup(_hlEditor, _primaryScrollView); - _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); } @Override From ff2e4337ef6dc432a6af06e9a17b71f29d339562 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Sun, 17 Nov 2024 14:25:11 +0800 Subject: [PATCH 6/8] improve initialization --- .../activity/DocumentEditAndViewFragment.java | 2 +- .../markdown/MarkdownSyntaxHighlighter.java | 2 +- .../textview/LineNumbersTextView.java | 65 ++++++++++++------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 8fab9ce722..09b59c72fe 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -155,7 +155,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { return; } - _lineNumbersView.setup(_hlEditor, _primaryScrollView); + _lineNumbersView.setup(_hlEditor); _lineNumbersView.setLineNumbersEnabled(_appSettings.getDocumentLineNumbersEnabled(_document.path)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && _appSettings.getSetWebViewFulldrawing()) { diff --git a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownSyntaxHighlighter.java b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownSyntaxHighlighter.java index 4c42ef809b..601b16f8ca 100644 --- a/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownSyntaxHighlighter.java +++ b/app/src/main/java/net/gsantner/markor/format/markdown/MarkdownSyntaxHighlighter.java @@ -36,7 +36,7 @@ public class MarkdownSyntaxHighlighter extends SyntaxHighlighterBase { private static final int MD_COLOR_LINK = 0xff1ea3fe; private static final int MD_COLOR_LIST = 0xffdaa521; private static final int MD_COLOR_QUOTE = 0xff88b04c; - private static final int MD_COLOR_CODEBLOCK = 0x448c8c8c; + private static final int MD_COLOR_CODEBLOCK = 0x2bafafaf; public MarkdownSyntaxHighlighter(AppSettings as) { super(as); diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index 18c9a36a59..47030b0578 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -11,27 +11,15 @@ import android.view.View; import android.view.ViewTreeObserver; import android.widget.EditText; -import android.widget.ScrollView; +import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatTextView; @SuppressWarnings("UnusedReturnValue") public class LineNumbersTextView extends AppCompatTextView { + private EditText editText; private LineNumbersDrawer lineNumbersDrawer; private boolean lineNumbersEnabled; - private ScrollView scrollView; - private final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { - private long lastTime; - - @Override - public void onScrollChanged() { - final long time = System.currentTimeMillis(); - if (time - lastTime > 125) { - lastTime = time; - refresh(); - } - } - }; public LineNumbersTextView(Context context) { super(context); @@ -68,23 +56,27 @@ public void refresh() { } } - public void setup(final EditText editText, ScrollView scrollView) { - this.scrollView = scrollView; - lineNumbersDrawer = new LineNumbersDrawer(editText, this); + public void setup(final @NonNull EditText editText) { + if (lineNumbersEnabled) { + setLineNumbersEnabled(false); + } + this.editText = editText; + this.lineNumbersDrawer = null; } public void setLineNumbersEnabled(final boolean enabled) { lineNumbersEnabled = enabled; - if (lineNumbersEnabled) { - lineNumbersDrawer.prepare(); - if (scrollView != null) { - scrollView.getViewTreeObserver().addOnScrollChangedListener(onScrollChangedListener); + + if (enabled) { + if (lineNumbersDrawer == null) { + lineNumbersDrawer = new LineNumbersDrawer(editText, this); } + lineNumbersDrawer.prepare(); } else { - lineNumbersDrawer.done(); - if (scrollView != null) { - scrollView.getViewTreeObserver().removeOnScrollChangedListener(onScrollChangedListener); + if (lineNumbersDrawer == null) { + return; } + lineNumbersDrawer.done(); } refresh(); } @@ -136,7 +128,20 @@ public void afterTextChanged(Editable editable) { } }; - public LineNumbersDrawer(final EditText editText, final LineNumbersTextView textView) { + private final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { + private long lastTime; + + @Override + public void onScrollChanged() { + final long time = System.currentTimeMillis(); + if (time - lastTime > 125) { + lastTime = time; + textView.refresh(); + } + } + }; + + public LineNumbersDrawer(final @NonNull EditText editText, final @NonNull LineNumbersTextView textView) { this.editText = editText; this.textView = textView; ORIGINAL_PADDING_LEFT = editText.getPaddingLeft(); @@ -243,11 +248,20 @@ private void setLineTracking(boolean enabled) { } } + private void setRefreshOnScrollChanged(final boolean enabled) { + if (enabled) { + editText.getViewTreeObserver().addOnScrollChangedListener(onScrollChangedListener); + } else { + editText.getViewTreeObserver().removeOnScrollChangedListener(onScrollChangedListener); + } + } + /** * Prepare for drawing line numbers. */ public void prepare() { setLineTracking(true); + setRefreshOnScrollChanged(true); textView.setVisibility(VISIBLE); editText.setPadding(EDITOR_PADDING_LEFT, editText.getPaddingTop(), editText.getPaddingRight(), editText.getPaddingBottom()); } @@ -329,6 +343,7 @@ public void draw(final Canvas canvas) { */ public void done() { setLineTracking(false); + setRefreshOnScrollChanged(false); maxNumberDigits = 0; textView.setWidth(0); textView.setVisibility(GONE); From 2df5a36a1bdc06d71b33a5ddb68678aec35c3aa3 Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Mon, 25 Nov 2024 11:12:13 +0800 Subject: [PATCH 7/8] minor improvements --- .../gsantner/markor/frontend/textview/LineNumbersTextView.java | 2 +- app/src/main/res/values/dimens.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java index 47030b0578..e89c6465ba 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/LineNumbersTextView.java @@ -91,7 +91,7 @@ static class LineNumbersDrawer { private final Paint paint = new Paint(); - private static final int NUMBER_PADDING_LEFT = 16; + private static final int NUMBER_PADDING_LEFT = 18; private static final int NUMBER_PADDING_RIGHT = 14; private static final int EDITOR_PADDING_LEFT = 8; private final int ORIGINAL_PADDING_LEFT; diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 307809d0e1..41e62a1ef7 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,6 +1,6 @@ - 10dp + 16dp 16dp 32dp 8dp From 4d43aaf71c5b60d8462324d6052a034e5315037c Mon Sep 17 00:00:00 2001 From: Li Guanglin Date: Sat, 14 Dec 2024 10:10:34 +0800 Subject: [PATCH 8/8] fix errors caused by merging --- .../frontend/textview/HighlightingEditor.java | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java index ec5ff49ca9..6b67cd0cc8 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java @@ -18,8 +18,8 @@ import android.text.Layout; import android.text.TextWatcher; import android.util.AttributeSet; -import android.view.ActionMode; import android.util.Log; +import android.view.ActionMode; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -131,7 +131,6 @@ public boolean onPreDraw() { @Override protected void onDraw(Canvas canvas) { - super.onDraw(canvas); try { super.onDraw(canvas); } catch (Exception e) { @@ -216,7 +215,9 @@ public void setDynamicHighlightingEnabled(final boolean enable) { recomputeHighlighting(); } - // public boolean isDynamicHighlightingEnabled() { return _isDynamicHighlightingEnabled; } + public boolean isDynamicHighlightingEnabled() { + return _isDynamicHighlightingEnabled; + } public void setHighlighter(final SyntaxHighlighterBase newHighlighter) { if (_hl != null) { @@ -558,4 +559,37 @@ public int moveCursorToBeginOfLine(int offset) { public boolean indexesValid(int... indexes) { return GsTextUtils.inRange(0, length(), indexes); } + + private void setupCustomOptions() { + setCustomSelectionActionModeCallback(new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Add custom items programmatically + menu.add(0, R.string.option_select_lines, 0, "☰"); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // Modify menu items here if necessary + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.string.option_select_lines: + HighlightingEditor.this.selectLines(); + return true; + default: + return false; + } + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Cleanup if needed + } + }); + } } \ No newline at end of file