diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-02-26 13:29:53 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-02-26 13:35:35 -0800 |
commit | 8f34567c71003505456a9b1a0d461a4e62883d70 (patch) | |
tree | 240e21488177c7bcd966a7473c009ca311ca331a /core/java/android/text/method | |
parent | 505312482782a600e997c91712f03f83c7a70428 (diff) | |
download | frameworks_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.java | 306 | ||||
-rw-r--r-- | core/java/android/text/method/MovementMethod.java | 1 | ||||
-rw-r--r-- | core/java/android/text/method/ScrollingMovementMethod.java | 155 |
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 |