From 0db38d5c679ffa6514cac23e698a0d4fc92b712c Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Thu, 14 Apr 2022 04:28:52 -0700 Subject: [PATCH] Improve showing selection and related functions, by @harshad1 (PR #1658) --- .../markor/activity/DocumentEditFragment.java | 10 ++-- .../ui/hleditor/HighlightingEditor.java | 16 +----- .../net/gsantner/opoc/util/StringUtils.java | 57 ++++++++++--------- 3 files changed, 38 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java index be91b4f33..fc1843c0a 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditFragment.java @@ -232,9 +232,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { } } - if (_hlEditor.indexesValid(startPos)) { - _hlEditor.setCursor(startPos); - } + StringUtils.setSelectionAndShow(_hlEditor, startPos); } @Override @@ -356,6 +354,7 @@ public void loadDocument() { _hlEditor.withAutoFormatDisabled(() -> _hlEditor.setText(content)); _hlEditor.setSelection(sel[0], sel[1]); + StringUtils.showSelection(_hlEditor); } checkTextChangeState(); @@ -630,6 +629,8 @@ private void setHorizontalScrollMode(final boolean wrap) { final boolean isCurrentlyWrap = _hsView == null || (_hlEditor.getParent() == _primaryScrollView); if (context != null && _hlEditor != null && isCurrentlyWrap != wrap) { + final int[] sel = StringUtils.getSelection(_hlEditor); + _primaryScrollView.removeAllViews(); if (_hsView != null) { _hsView.removeAllViews(); @@ -647,7 +648,8 @@ private void setHorizontalScrollMode(final boolean wrap) { _primaryScrollView.addView(_hlEditor); } - StringUtils.showSelection(_hlEditor); + // Run after layout() of immediate parent completes + (wrap ? _primaryScrollView : _hsView).post(() -> StringUtils.setSelectionAndShow(_hlEditor, sel[0], sel[1])); } } diff --git a/app/src/main/java/net/gsantner/markor/ui/hleditor/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/ui/hleditor/HighlightingEditor.java index 9f6e05ad2..f03ed0a97 100644 --- a/app/src/main/java/net/gsantner/markor/ui/hleditor/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/ui/hleditor/HighlightingEditor.java @@ -290,13 +290,7 @@ public void setHighlightingEnabled(final boolean enable) { public boolean indexesValid(int... indexes) { - int len = length(); - for (int index : indexes) { - if (index < 0 || index > len) { - return false; - } - } - return true; + return StringUtils.inRange(0, length(), indexes); } @Override @@ -330,14 +324,6 @@ protected void onSelectionChanged(int selStart, int selEnd) { } } - public void setCursor(final int index) { - if (!hasFocus()) { - requestFocus(); - } - post(() -> StringUtils.showSelection(this, index, index)); - post(() ->setSelection(index)); - } - public void setAccessibilityEnabled(final boolean enabled) { _accessibilityEnabled = enabled; } diff --git a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java index 8cff164b2..d91d9fa0d 100644 --- a/app/src/main/java/net/gsantner/opoc/util/StringUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/StringUtils.java @@ -11,7 +11,6 @@ import android.graphics.Rect; import android.text.Layout; -import android.text.TextUtils; import android.util.Base64; import android.widget.EditText; import android.widget.TextView; @@ -32,15 +31,17 @@ private StringUtils() { } public static boolean isValidIndex(final CharSequence s, final int... indices) { - if (s != null && indices.length > 0) { - for (final int i : indices) { - if (i < 0 || i >= s.length()) { - return false; - } + return s != null && inRange(0, s.length() - 1, indices); + } + + // Checks if all values are in [min, max] _inclusive_ + public static boolean inRange(final int min, final int max, final int... values) { + for (final int i : values) { + if (i < min || i > max) { + return false; } - return true; } - return false; + return true; } public static int getLineStart(CharSequence s, int start) { @@ -326,8 +327,7 @@ public static void selectLines(final EditText edit, final List position final CharSequence text = edit.getText(); if (positions.size() == 1) { // Case 1 index final int posn = StringUtils.getIndexFromLineOffset(text, positions.get(0), 0); - showSelection(edit, posn, posn); - edit.setSelection(posn); + setSelectionAndShow(edit, posn); } else if (positions.size() > 1) { final TreeSet pSet = new TreeSet<>(positions); final int selStart, selEnd; @@ -342,13 +342,12 @@ public static void selectLines(final EditText edit, final List position (pSet.contains(i) ? sel : unsel).add(lines[i]); } sel.addAll(unsel); - final String newText = TextUtils.join("\n", sel); + final String newText = android.text.TextUtils.join("\n", sel); edit.setText(newText); selStart = 0; selEnd = StringUtils.getIndexFromLineOffset(newText, positions.size() - 1, 0); } - showSelection(edit, selStart, selEnd); - edit.setSelection(selStart, selEnd); + setSelectionAndShow(edit, selStart, selEnd); } } @@ -399,24 +398,30 @@ public static void showSelection(final TextView text, final int start, final int // Region in X - as handling RTL, text alignment, and centred text etc is // a huge pain (see TextView.bringPointIntoView), we use a very simple solution. // ------------------------------------------------------------ - - final int endLeft = (int) layout.getPrimaryHorizontal(_end); final int startLeft = (int) layout.getPrimaryHorizontal(_start); - region.left = Math.min(startLeft, endLeft); - region.right = Math.max(startLeft, endLeft); - - if (region.left == region.right) { - // make sure rect width > 0 - region.right += 1; - } else if (region.width() > viewSize.width()) { - // Make sure selStart is in rect if possible - region.left = startLeft; - region.right = region.left + viewSize.width(); - } + final int halfWidth = viewSize.width() / 2; + // Push the start to the middle of the screen + region.left = startLeft - halfWidth; + region.right = startLeft + halfWidth; + // Call in post to try to make sure we run after any pending actions text.post(() -> text.requestRectangleOnScreen(region)); } + public static void setSelectionAndShow(final EditText edit, final int start, final int... end) { + final int _end = end != null && end.length > 0 ? end[0] : start; + if (inRange(0, edit.length(), start, _end)) { + edit.post(() -> { + if (!edit.hasFocus()) { + edit.requestFocus(); + } + + edit.setSelection(start, _end); + edit.post(() -> showSelection(edit, start, _end)); + }); + } + } + // Search for matching pairs of backticks // interpolate contents of backtick pair as SimpleDateFormat public static String interpolateEscapedDateTime(final String snip) {