summaryrefslogtreecommitdiffstats
path: root/core/java/android/text/method
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-02-26 13:29:53 -0800
committerJeff Brown <jeffbrown@google.com>2011-02-26 13:35:35 -0800
commit8f34567c71003505456a9b1a0d461a4e62883d70 (patch)
tree240e21488177c7bcd966a7473c009ca311ca331a /core/java/android/text/method
parent505312482782a600e997c91712f03f83c7a70428 (diff)
downloadframeworks_base-8f34567c71003505456a9b1a0d461a4e62883d70.zip
frameworks_base-8f34567c71003505456a9b1a0d461a4e62883d70.tar.gz
frameworks_base-8f34567c71003505456a9b1a0d461a4e62883d70.tar.bz2
Add scroll wheel support to TextView.
Change-Id: I6e4258c50b0d754dccf07266ff4b2abcbccd733a
Diffstat (limited to 'core/java/android/text/method')
-rw-r--r--core/java/android/text/method/BaseMovementMethod.java306
-rw-r--r--core/java/android/text/method/MovementMethod.java1
-rw-r--r--core/java/android/text/method/ScrollingMovementMethod.java155
3 files changed, 317 insertions, 145 deletions
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 2be18d6..94c6ed0 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -18,6 +18,7 @@ package android.text.method;
import android.text.Layout;
import android.text.Spannable;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.TextView;
@@ -88,6 +89,39 @@ public class BaseMovementMethod implements MovementMethod {
return false;
}
+ @Override
+ public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ final float vscroll;
+ final float hscroll;
+ if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+ vscroll = 0;
+ hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ } else {
+ vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ }
+
+ boolean handled = false;
+ if (hscroll < 0) {
+ handled |= scrollLeft(widget, text, (int)Math.ceil(-hscroll));
+ } else if (hscroll > 0) {
+ handled |= scrollRight(widget, text, (int)Math.ceil(hscroll));
+ }
+ if (vscroll < 0) {
+ handled |= scrollUp(widget, text, (int)Math.ceil(-vscroll));
+ } else if (vscroll > 0) {
+ handled |= scrollDown(widget, text, (int)Math.ceil(vscroll));
+ }
+ return handled;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Gets the meta state used for movement using the modifiers tracked by the text
* buffer as well as those present in the key event.
@@ -342,4 +376,276 @@ public class BaseMovementMethod implements MovementMethod {
protected boolean end(TextView widget, Spannable buffer) {
return false;
}
+
+ private int getTopLine(TextView widget) {
+ return widget.getLayout().getLineForVertical(widget.getScrollY());
+ }
+
+ private int getBottomLine(TextView widget) {
+ return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
+ }
+
+ private int getInnerWidth(TextView widget) {
+ return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight();
+ }
+
+ private int getInnerHeight(TextView widget) {
+ return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
+ }
+
+ private int getCharacterWidth(TextView widget) {
+ return (int) Math.ceil(widget.getPaint().getFontSpacing());
+ }
+
+ private int getScrollBoundsLeft(TextView widget) {
+ final Layout layout = widget.getLayout();
+ final int topLine = getTopLine(widget);
+ final int bottomLine = getBottomLine(widget);
+ if (topLine > bottomLine) {
+ return 0;
+ }
+ int left = Integer.MAX_VALUE;
+ for (int line = topLine; line <= bottomLine; line++) {
+ final int lineLeft = (int) Math.floor(layout.getLineLeft(line));
+ if (lineLeft < left) {
+ left = lineLeft;
+ }
+ }
+ return left;
+ }
+
+ private int getScrollBoundsRight(TextView widget) {
+ final Layout layout = widget.getLayout();
+ final int topLine = getTopLine(widget);
+ final int bottomLine = getBottomLine(widget);
+ if (topLine > bottomLine) {
+ return 0;
+ }
+ int right = Integer.MIN_VALUE;
+ for (int line = topLine; line <= bottomLine; line++) {
+ final int lineRight = (int) Math.ceil(layout.getLineRight(line));
+ if (lineRight > right) {
+ right = lineRight;
+ }
+ }
+ return right;
+ }
+
+ /**
+ * Performs a scroll left action.
+ * Scrolls left by the specified number of characters.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of characters to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLeft(TextView widget, Spannable buffer, int amount) {
+ final int minScrollX = getScrollBoundsLeft(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX > minScrollX) {
+ scrollX = Math.max(scrollX - getCharacterWidth(widget) * amount, minScrollX);
+ widget.scrollTo(scrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll right action.
+ * Scrolls right by the specified number of characters.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of characters to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollRight(TextView widget, Spannable buffer, int amount) {
+ final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX < maxScrollX) {
+ scrollX = Math.min(scrollX + getCharacterWidth(widget) * amount, maxScrollX);
+ widget.scrollTo(scrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll up action.
+ * Scrolls up by the specified number of lines.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of lines to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollUp(TextView widget, Spannable buffer, int amount) {
+ final Layout layout = widget.getLayout();
+ final int top = widget.getScrollY();
+ int topLine = layout.getLineForVertical(top);
+ if (layout.getLineTop(topLine) == top) {
+ // If the top line is partially visible, bring it all the way
+ // into view; otherwise, bring the previous line into view.
+ topLine -= 1;
+ }
+ if (topLine >= 0) {
+ topLine = Math.max(topLine - amount + 1, 0);
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll down action.
+ * Scrolls down by the specified number of lines.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @param amount The number of lines to scroll by. Must be at least 1.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollDown(TextView widget, Spannable buffer, int amount) {
+ final Layout layout = widget.getLayout();
+ final int innerHeight = getInnerHeight(widget);
+ final int bottom = widget.getScrollY() + innerHeight;
+ int bottomLine = layout.getLineForVertical(bottom);
+ if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
+ // Less than a pixel of this line is out of view,
+ // so we must have tried to make it entirely in view
+ // and now want the next line to be in view instead.
+ bottomLine += 1;
+ }
+ final int limit = layout.getLineCount() - 1;
+ if (bottomLine <= limit) {
+ bottomLine = Math.min(bottomLine + amount - 1, limit);
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(bottomLine + 1) - innerHeight);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll page up action.
+ * Scrolls up by one page.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollPageUp(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int top = widget.getScrollY() - getInnerHeight(widget);
+ int topLine = layout.getLineForVertical(top);
+ if (topLine >= 0) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll page up action.
+ * Scrolls down by one page.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollPageDown(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int innerHeight = getInnerHeight(widget);
+ final int bottom = widget.getScrollY() + innerHeight + innerHeight;
+ int bottomLine = layout.getLineForVertical(bottom);
+ if (bottomLine <= layout.getLineCount() - 1) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(bottomLine + 1) - innerHeight);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to top action.
+ * Scrolls to the top of the document.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollTop(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ if (getTopLine(widget) >= 0) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to bottom action.
+ * Scrolls to the bottom of the document.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollBottom(TextView widget, Spannable buffer) {
+ final Layout layout = widget.getLayout();
+ final int lineCount = layout.getLineCount();
+ if (getBottomLine(widget) <= lineCount - 1) {
+ Touch.scrollTo(widget, layout, widget.getScrollX(),
+ layout.getLineTop(lineCount) - getInnerHeight(widget));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to line start action.
+ * Scrolls to the start of the line.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLineStart(TextView widget, Spannable buffer) {
+ final int minScrollX = getScrollBoundsLeft(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX > minScrollX) {
+ widget.scrollTo(minScrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Performs a scroll to line end action.
+ * Scrolls to the end of the line.
+ *
+ * @param widget The text view.
+ * @param buffer The text buffer.
+ * @return True if the event was handled.
+ * @hide
+ */
+ protected boolean scrollLineEnd(TextView widget, Spannable buffer) {
+ final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
+ int scrollX = widget.getScrollX();
+ if (scrollX < maxScrollX) {
+ widget.scrollTo(maxScrollX, widget.getScrollY());
+ return true;
+ }
+ return false;
+ }
}
diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java
index 9167676..01979fd 100644
--- a/core/java/android/text/method/MovementMethod.java
+++ b/core/java/android/text/method/MovementMethod.java
@@ -47,6 +47,7 @@ public interface MovementMethod {
public void onTakeFocus(TextView widget, Spannable text, int direction);
public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event);
public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event);
+ public boolean onGenericMotionEvent(TextView widget, Spannable text, MotionEvent event);
/**
* Returns true if this movement method allows arbitrary selection
diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java
index 194ecc1..b9f5d5f 100644
--- a/core/java/android/text/method/ScrollingMovementMethod.java
+++ b/core/java/android/text/method/ScrollingMovementMethod.java
@@ -25,189 +25,54 @@ import android.view.View;
* A movement method that interprets movement keys by scrolling the text buffer.
*/
public class ScrollingMovementMethod extends BaseMovementMethod implements MovementMethod {
- private int getTopLine(TextView widget) {
- return widget.getLayout().getLineForVertical(widget.getScrollY());
- }
-
- private int getBottomLine(TextView widget) {
- return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
- }
-
- private int getInnerWidth(TextView widget) {
- return widget.getWidth() - widget.getTotalPaddingLeft() - widget.getTotalPaddingRight();
- }
-
- private int getInnerHeight(TextView widget) {
- return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
- }
-
- private int getCharacterWidth(TextView widget) {
- return (int) Math.ceil(widget.getPaint().getFontSpacing());
- }
-
- private int getScrollBoundsLeft(TextView widget) {
- final Layout layout = widget.getLayout();
- final int topLine = getTopLine(widget);
- final int bottomLine = getBottomLine(widget);
- if (topLine > bottomLine) {
- return 0;
- }
- int left = Integer.MAX_VALUE;
- for (int line = topLine; line <= bottomLine; line++) {
- final int lineLeft = (int) Math.floor(layout.getLineLeft(line));
- if (lineLeft < left) {
- left = lineLeft;
- }
- }
- return left;
- }
-
- private int getScrollBoundsRight(TextView widget) {
- final Layout layout = widget.getLayout();
- final int topLine = getTopLine(widget);
- final int bottomLine = getBottomLine(widget);
- if (topLine > bottomLine) {
- return 0;
- }
- int right = Integer.MIN_VALUE;
- for (int line = topLine; line <= bottomLine; line++) {
- final int lineRight = (int) Math.ceil(layout.getLineRight(line));
- if (lineRight > right) {
- right = lineRight;
- }
- }
- return right;
- }
-
@Override
protected boolean left(TextView widget, Spannable buffer) {
- final int minScrollX = getScrollBoundsLeft(widget);
- int scrollX = widget.getScrollX();
- if (scrollX > minScrollX) {
- scrollX = Math.max(scrollX - getCharacterWidth(widget), minScrollX);
- widget.scrollTo(scrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLeft(widget, buffer, 1);
}
@Override
protected boolean right(TextView widget, Spannable buffer) {
- final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
- int scrollX = widget.getScrollX();
- if (scrollX < maxScrollX) {
- scrollX = Math.min(scrollX + getCharacterWidth(widget), maxScrollX);
- widget.scrollTo(scrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollRight(widget, buffer, 1);
}
@Override
protected boolean up(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int top = widget.getScrollY();
- int topLine = layout.getLineForVertical(top);
- if (layout.getLineTop(topLine) == top) {
- // If the top line is partially visible, bring it all the way
- // into view; otherwise, bring the previous line into view.
- topLine -= 1;
- }
- if (topLine >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
- return true;
- }
- return false;
+ return scrollUp(widget, buffer, 1);
}
@Override
protected boolean down(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int innerHeight = getInnerHeight(widget);
- final int bottom = widget.getScrollY() + innerHeight;
- int bottomLine = layout.getLineForVertical(bottom);
- if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
- // Less than a pixel of this line is out of view,
- // so we must have tried to make it entirely in view
- // and now want the next line to be in view instead.
- bottomLine += 1;
- }
- if (bottomLine <= layout.getLineCount() - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(bottomLine + 1) - innerHeight);
- return true;
- }
- return false;
+ return scrollDown(widget, buffer, 1);
}
@Override
protected boolean pageUp(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int top = widget.getScrollY() - getInnerHeight(widget);
- int topLine = layout.getLineForVertical(top);
- if (topLine >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(topLine));
- return true;
- }
- return false;
+ return scrollPageUp(widget, buffer);
}
@Override
protected boolean pageDown(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int innerHeight = getInnerHeight(widget);
- final int bottom = widget.getScrollY() + innerHeight + innerHeight;
- int bottomLine = layout.getLineForVertical(bottom);
- if (bottomLine <= layout.getLineCount() - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(bottomLine + 1) - innerHeight);
- return true;
- }
- return false;
+ return scrollPageDown(widget, buffer);
}
@Override
protected boolean top(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- if (getTopLine(widget) >= 0) {
- Touch.scrollTo(widget, layout, widget.getScrollX(), layout.getLineTop(0));
- return true;
- }
- return false;
+ return scrollTop(widget, buffer);
}
@Override
protected boolean bottom(TextView widget, Spannable buffer) {
- final Layout layout = widget.getLayout();
- final int lineCount = layout.getLineCount();
- if (getBottomLine(widget) <= lineCount - 1) {
- Touch.scrollTo(widget, layout, widget.getScrollX(),
- layout.getLineTop(lineCount) - getInnerHeight(widget));
- return true;
- }
- return false;
+ return scrollBottom(widget, buffer);
}
@Override
protected boolean lineStart(TextView widget, Spannable buffer) {
- final int minScrollX = getScrollBoundsLeft(widget);
- int scrollX = widget.getScrollX();
- if (scrollX > minScrollX) {
- widget.scrollTo(minScrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLineStart(widget, buffer);
}
@Override
protected boolean lineEnd(TextView widget, Spannable buffer) {
- final int maxScrollX = getScrollBoundsRight(widget) - getInnerWidth(widget);
- int scrollX = widget.getScrollX();
- if (scrollX < maxScrollX) {
- widget.scrollTo(maxScrollX, widget.getScrollY());
- return true;
- }
- return false;
+ return scrollLineEnd(widget, buffer);
}
@Override