ScrollingMovementMethod.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.text.method; 18 19import android.util.Log; 20import android.view.KeyEvent; 21import android.view.MotionEvent; 22import android.text.*; 23import android.widget.TextView; 24import android.view.View; 25 26public class 27ScrollingMovementMethod 28implements MovementMethod 29{ 30 /** 31 * Scrolls the text to the left if possible. 32 */ 33 protected boolean left(TextView widget, Spannable buffer) { 34 Layout layout = widget.getLayout(); 35 36 int scrolly = widget.getScrollY(); 37 int scr = widget.getScrollX(); 38 int em = Math.round(layout.getPaint().getFontSpacing()); 39 40 int padding = widget.getTotalPaddingTop() + 41 widget.getTotalPaddingBottom(); 42 int top = layout.getLineForVertical(scrolly); 43 int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - 44 padding); 45 int left = Integer.MAX_VALUE; 46 47 for (int i = top; i <= bottom; i++) { 48 left = (int) Math.min(left, layout.getLineLeft(i)); 49 } 50 51 if (scr > left) { 52 int s = Math.max(scr - em, left); 53 widget.scrollTo(s, widget.getScrollY()); 54 return true; 55 } 56 57 return false; 58 } 59 60 /** 61 * Scrolls the text to the right if possible. 62 */ 63 protected boolean right(TextView widget, Spannable buffer) { 64 Layout layout = widget.getLayout(); 65 66 int scrolly = widget.getScrollY(); 67 int scr = widget.getScrollX(); 68 int em = Math.round(layout.getPaint().getFontSpacing()); 69 70 int padding = widget.getTotalPaddingTop() + 71 widget.getTotalPaddingBottom(); 72 int top = layout.getLineForVertical(scrolly); 73 int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - 74 padding); 75 int right = 0; 76 77 for (int i = top; i <= bottom; i++) { 78 right = (int) Math.max(right, layout.getLineRight(i)); 79 } 80 81 padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); 82 if (scr < right - (widget.getWidth() - padding)) { 83 int s = Math.min(scr + em, right - (widget.getWidth() - padding)); 84 widget.scrollTo(s, widget.getScrollY()); 85 return true; 86 } 87 88 return false; 89 } 90 91 /** 92 * Scrolls the text up if possible. 93 */ 94 protected boolean up(TextView widget, Spannable buffer) { 95 Layout layout = widget.getLayout(); 96 97 int areatop = widget.getScrollY(); 98 int line = layout.getLineForVertical(areatop); 99 int linetop = layout.getLineTop(line); 100 101 // If the top line is partially visible, bring it all the way 102 // into view; otherwise, bring the previous line into view. 103 if (areatop == linetop) 104 line--; 105 106 if (line >= 0) { 107 Touch.scrollTo(widget, layout, 108 widget.getScrollX(), layout.getLineTop(line)); 109 return true; 110 } 111 112 return false; 113 } 114 115 /** 116 * Scrolls the text down if possible. 117 */ 118 protected boolean down(TextView widget, Spannable buffer) { 119 Layout layout = widget.getLayout(); 120 121 int padding = widget.getTotalPaddingTop() + 122 widget.getTotalPaddingBottom(); 123 124 int areabot = widget.getScrollY() + widget.getHeight() - padding; 125 int line = layout.getLineForVertical(areabot); 126 127 if (layout.getLineTop(line+1) < areabot + 1) { 128 // Less than a pixel of this line is out of view, 129 // so we must have tried to make it entirely in view 130 // and now want the next line to be in view instead. 131 132 line++; 133 } 134 135 if (line <= layout.getLineCount() - 1) { 136 widget.scrollTo(widget.getScrollX(), layout.getLineTop(line+1) - 137 (widget.getHeight() - padding)); 138 Touch.scrollTo(widget, layout, 139 widget.getScrollX(), widget.getScrollY()); 140 return true; 141 } 142 143 return false; 144 } 145 146 public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 147 boolean handled = false; 148 149 switch (keyCode) { 150 case KeyEvent.KEYCODE_DPAD_LEFT: 151 handled |= left(widget, buffer); 152 break; 153 154 case KeyEvent.KEYCODE_DPAD_RIGHT: 155 handled |= right(widget, buffer); 156 break; 157 158 case KeyEvent.KEYCODE_DPAD_UP: 159 handled |= up(widget, buffer); 160 break; 161 162 case KeyEvent.KEYCODE_DPAD_DOWN: 163 handled |= down(widget, buffer); 164 break; 165 } 166 167 return handled; 168 } 169 170 public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 171 return false; 172 } 173 174 public boolean onTouchEvent(TextView widget, Spannable buffer, 175 MotionEvent event) { 176 return Touch.onTouchEvent(widget, buffer, event); 177 } 178 179 public boolean onTrackballEvent(TextView widget, Spannable buffer, 180 MotionEvent event) { 181 boolean handled = false; 182 int x = (int) event.getX(); 183 int y = (int) event.getY(); 184 185 for (; y < 0; y++) { 186 handled |= up(widget, buffer); 187 } 188 for (; y > 0; y--) { 189 handled |= down(widget, buffer); 190 } 191 192 for (; x < 0; x++) { 193 handled |= left(widget, buffer); 194 } 195 for (; x > 0; x--) { 196 handled |= right(widget, buffer); 197 } 198 199 return handled; 200 } 201 202 public void initialize(TextView widget, Spannable text) { } 203 204 public boolean canSelectArbitrarily() { 205 return false; 206 } 207 208 public void onTakeFocus(TextView widget, Spannable text, int dir) { 209 Layout layout = widget.getLayout(); 210 211 if (layout != null && (dir & View.FOCUS_FORWARD) != 0) { 212 widget.scrollTo(widget.getScrollX(), 213 layout.getLineTop(0)); 214 } 215 if (layout != null && (dir & View.FOCUS_BACKWARD) != 0) { 216 int padding = widget.getTotalPaddingTop() + 217 widget.getTotalPaddingBottom(); 218 int line = layout.getLineCount() - 1; 219 220 widget.scrollTo(widget.getScrollX(), 221 layout.getLineTop(line+1) - 222 (widget.getHeight() - padding)); 223 } 224 } 225 226 public static MovementMethod getInstance() { 227 if (sInstance == null) 228 sInstance = new ScrollingMovementMethod(); 229 230 return sInstance; 231 } 232 233 private static ScrollingMovementMethod sInstance; 234} 235