Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce08379e authored by Maryam Garrett's avatar Maryam Garrett
Browse files

Improves the touch-based text selection UI in text boxes.

With this change, when a user is in "text select" mode, they
can swipe any part of the text. This changes the behavior of
the touch-based select in 2 ways (behavior for cursor-based
select remains the same):

1. You can now indicate where your select will start. Before
this change, the select always started at the last cursor
position.

2. Selection will respect word boundaries. Before this
change the selection would be character to character. Since
users don't have a fine grain level of control over touch
events, this would often lead to incomplete selections.
parent 51e45ff0
Loading
Loading
Loading
Loading
+93 −32
Original line number Diff line number Diff line
@@ -133,6 +133,35 @@ implements MovementMethod
        }
    }

    private int getOffset(int x, int y, TextView widget){
      // Converts the absolute X,Y coordinates to the character offset for the
      // character whose position is closest to the specified
      // horizontal position.
      x -= widget.getTotalPaddingLeft();
      y -= widget.getTotalPaddingTop();

      // Clamp the position to inside of the view.
      if (x < 0) {
          x = 0;
      } else if (x >= (widget.getWidth()-widget.getTotalPaddingRight())) {
          x = widget.getWidth()-widget.getTotalPaddingRight() - 1;
      }
      if (y < 0) {
          y = 0;
      } else if (y >= (widget.getHeight()-widget.getTotalPaddingBottom())) {
          y = widget.getHeight()-widget.getTotalPaddingBottom() - 1;
      }

      x += widget.getScrollX();
      y += widget.getScrollY();

      Layout layout = widget.getLayout();
      int line = layout.getLineForVertical(y);

      int offset = layout.getOffsetForHorizontal(line, x);
      return offset;
    }

    public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
        if (executeDown(widget, buffer, keyCode)) {
            MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
@@ -213,7 +242,59 @@ implements MovementMethod
        boolean handled = Touch.onTouchEvent(widget, buffer, event);

        if (widget.isFocused() && !widget.didTouchFocusSelect()) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
              boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
                              KeyEvent.META_SHIFT_ON) == 1) ||
                            (MetaKeyKeyListener.getMetaState(buffer,
                              MetaKeyKeyListener.META_SELECTING) != 0);
              if (cap) {
                  int x = (int) event.getX();
                  int y = (int) event.getY();
                  int offset = getOffset(x, y, widget);

                  buffer.setSpan(LAST_TAP_DOWN, offset, offset,
                                 Spannable.SPAN_POINT_POINT);
              }
            } else if (event.getAction() == MotionEvent.ACTION_MOVE ) {
              boolean cap = (MetaKeyKeyListener.getMetaState(buffer,
                              KeyEvent.META_SHIFT_ON) == 1) ||
                            (MetaKeyKeyListener.getMetaState(buffer,
                              MetaKeyKeyListener.META_SELECTING) != 0);

              if (cap) {
                // Update selection as we're moving the selection area.

                // Get the current touch position
                int x = (int) event.getX();
                int y = (int) event.getY();
                int offset = getOffset(x, y, widget);

                // Get the last down touch position (the position at which the
                // user started the selection)
                int lastDownOffset = buffer.getSpanStart(LAST_TAP_DOWN);

                // Compute the selection boundries
                int spanstart;
                int spanend;
                if (offset >= lastDownOffset) {
                  // expand to from word start of the original tap to new word
                  // end, since we are selecting "forwards"
                  spanstart = findWordStart(buffer, lastDownOffset);
                  spanend = findWordEnd(buffer, offset);
                } else {
                  // Expand to from new word start to word end of the original
                  // tap since we are selecting "backwards".
                  // The spanend will always need to be associated with the touch
                  // up position, so that refining the selection with the
                  // trackball will work as expected.
                  spanstart = findWordEnd(buffer, lastDownOffset);
                  spanend = findWordStart(buffer, offset);
                }

                Selection.setSelection(buffer, spanstart, spanend);
                return true;
              }
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                // If we have scrolled, then the up shouldn't move the cursor,
                // but we do need to make sure the cursor is still visible at
                // the current scroll offset to avoid the scroll jumping later
@@ -226,29 +307,7 @@ implements MovementMethod

                int x = (int) event.getX();
                int y = (int) event.getY();

                x -= widget.getTotalPaddingLeft();
                y -= widget.getTotalPaddingTop();

                // Clamp the position to inside of the view.
                if (x < 0) {
                    x = 0;
                } else if (x >= (widget.getWidth()-widget.getTotalPaddingRight())) {
                    x = widget.getWidth()-widget.getTotalPaddingRight() - 1;
                }
                if (y < 0) {
                    y = 0;
                } else if (y >= (widget.getHeight()-widget.getTotalPaddingBottom())) {
                    y = widget.getHeight()-widget.getTotalPaddingBottom() - 1;
                }
                
                x += widget.getScrollX();
                y += widget.getScrollY();

                Layout layout = widget.getLayout();
                int line = layout.getLineForVertical(y);
                
                int off = layout.getOffsetForHorizontal(line, x);
                int off = getOffset(x, y, widget);

                // XXX should do the same adjust for x as we do for the line.

@@ -278,7 +337,7 @@ implements MovementMethod
                }

                if (cap) {
                    Selection.extendSelection(buffer, off);
                    buffer.removeSpan(LAST_TAP_DOWN);
                } else if (doubletap) {
                    Selection.setSelection(buffer,
                                           findWordStart(buffer, off),
@@ -395,5 +454,7 @@ implements MovementMethod
        return sInstance;
    }


    private static final Object LAST_TAP_DOWN = new Object();
    private static ArrowKeyMovementMethod sInstance;
}