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 17 package android.widget; 18 19 import android.graphics.Canvas; 20 import android.graphics.ColorFilter; 21 import android.graphics.PixelFormat; 22 import android.graphics.Rect; 23 import android.graphics.drawable.Drawable; 24 25 /** 26 * This is only used by View for displaying its scroll bars. It should probably 27 * be moved in to the view package since it is used in that lower-level layer. 28 * For now, we'll hide it so it can be cleaned up later. 29 * {@hide} 30 */ 31 public class ScrollBarDrawable extends Drawable { 32 private Drawable mVerticalTrack; 33 private Drawable mHorizontalTrack; 34 private Drawable mVerticalThumb; 35 private Drawable mHorizontalThumb; 36 private int mRange; 37 private int mOffset; 38 private int mExtent; 39 private boolean mVertical; 40 private boolean mChanged; 41 private boolean mRangeChanged; 42 private final Rect mTempBounds = new Rect(); 43 private boolean mAlwaysDrawHorizontalTrack; 44 private boolean mAlwaysDrawVerticalTrack; 45 46 public ScrollBarDrawable() { 47 } 48 49 /** 50 * Indicate whether the horizontal scrollbar track should always be drawn regardless of the 51 * extent. Defaults to false. 52 * 53 * @param alwaysDrawTrack Set to true if the track should always be drawn 54 */ 55 public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) { 56 mAlwaysDrawHorizontalTrack = alwaysDrawTrack; 57 } 58 59 /** 60 * Indicate whether the vertical scrollbar track should always be drawn regardless of the 61 * extent. Defaults to false. 62 * 63 * @param alwaysDrawTrack Set to true if the track should always be drawn 64 */ 65 public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) { 66 mAlwaysDrawVerticalTrack = alwaysDrawTrack; 67 } 68 69 /** 70 * Indicates whether the vertical scrollbar track should always be drawn regardless of the 71 * extent. 72 */ 73 public boolean getAlwaysDrawVerticalTrack() { 74 return mAlwaysDrawVerticalTrack; 75 } 76 77 /** 78 * Indicates whether the horizontal scrollbar track should always be drawn regardless of the 79 * extent. 80 */ 81 public boolean getAlwaysDrawHorizontalTrack() { 82 return mAlwaysDrawHorizontalTrack; 83 } 84 85 public void setParameters(int range, int offset, int extent, boolean vertical) { 86 if (mVertical != vertical) { 87 mChanged = true; 88 } 89 90 if (mRange != range || mOffset != offset || mExtent != extent) { 91 mRangeChanged = true; 92 } 93 94 mRange = range; 95 mOffset = offset; 96 mExtent = extent; 97 mVertical = vertical; 98 } 99 100 @Override 101 public void draw(Canvas canvas) { 102 final boolean vertical = mVertical; 103 final int extent = mExtent; 104 final int range = mRange; 105 106 boolean drawTrack = true; 107 boolean drawThumb = true; 108 if (extent <= 0 || range <= extent) { 109 drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack; 110 drawThumb = false; 111 } 112 113 Rect r = getBounds(); 114 if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) { 115 return; 116 } 117 if (drawTrack) { 118 drawTrack(canvas, r, vertical); 119 } 120 121 if (drawThumb) { 122 int size = vertical ? r.height() : r.width(); 123 int thickness = vertical ? r.width() : r.height(); 124 int length = Math.round((float) size * extent / range); 125 int offset = Math.round((float) (size - length) * mOffset / (range - extent)); 126 127 // avoid the tiny thumb 128 int minLength = thickness * 2; 129 if (length < minLength) { 130 length = minLength; 131 } 132 // avoid the too-big thumb 133 if (offset + length > size) { 134 offset = size - length; 135 } 136 137 drawThumb(canvas, r, offset, length, vertical); 138 } 139 } 140 141 @Override 142 protected void onBoundsChange(Rect bounds) { 143 super.onBoundsChange(bounds); 144 mChanged = true; 145 } 146 147 protected void drawTrack(Canvas canvas, Rect bounds, boolean vertical) { 148 Drawable track; 149 if (vertical) { 150 track = mVerticalTrack; 151 } else { 152 track = mHorizontalTrack; 153 } 154 if (track != null) { 155 if (mChanged) { 156 track.setBounds(bounds); 157 } 158 track.draw(canvas); 159 } 160 } 161 162 protected void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) { 163 final Rect thumbRect = mTempBounds; 164 final boolean changed = mRangeChanged || mChanged; 165 if (changed) { 166 if (vertical) { 167 thumbRect.set(bounds.left, bounds.top + offset, 168 bounds.right, bounds.top + offset + length); 169 } else { 170 thumbRect.set(bounds.left + offset, bounds.top, 171 bounds.left + offset + length, bounds.bottom); 172 } 173 } 174 175 if (vertical) { 176 if (mVerticalThumb != null) { 177 final Drawable thumb = mVerticalThumb; 178 if (changed) thumb.setBounds(thumbRect); 179 thumb.draw(canvas); 180 } 181 } else { 182 if (mHorizontalThumb != null) { 183 final Drawable thumb = mHorizontalThumb; 184 if (changed) thumb.setBounds(thumbRect); 185 thumb.draw(canvas); 186 } 187 } 188 } 189 190 public void setVerticalThumbDrawable(Drawable thumb) { 191 if (thumb != null) { 192 mVerticalThumb = thumb; 193 } 194 } 195 196 public void setVerticalTrackDrawable(Drawable track) { 197 mVerticalTrack = track; 198 } 199 200 public void setHorizontalThumbDrawable(Drawable thumb) { 201 if (thumb != null) { 202 mHorizontalThumb = thumb; 203 } 204 } 205 206 public void setHorizontalTrackDrawable(Drawable track) { 207 mHorizontalTrack = track; 208 } 209 210 public int getSize(boolean vertical) { 211 if (vertical) { 212 return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() : 213 mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0; 214 } else { 215 return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() : 216 mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0; 217 } 218 } 219 220 @Override 221 public void setAlpha(int alpha) { 222 if (mVerticalTrack != null) { 223 mVerticalTrack.setAlpha(alpha); 224 } 225 if (mVerticalThumb != null) { 226 mVerticalThumb.setAlpha(alpha); 227 } 228 if (mHorizontalTrack != null) { 229 mHorizontalTrack.setAlpha(alpha); 230 } 231 if (mHorizontalThumb != null) { 232 mHorizontalThumb.setAlpha(alpha); 233 } 234 } 235 236 @Override 237 public int getAlpha() { 238 // All elements should have same alpha, just return one of them 239 return mVerticalThumb.getAlpha(); 240 } 241 242 @Override 243 public void setColorFilter(ColorFilter cf) { 244 if (mVerticalTrack != null) { 245 mVerticalTrack.setColorFilter(cf); 246 } 247 if (mVerticalThumb != null) { 248 mVerticalThumb.setColorFilter(cf); 249 } 250 if (mHorizontalTrack != null) { 251 mHorizontalTrack.setColorFilter(cf); 252 } 253 if (mHorizontalThumb != null) { 254 mHorizontalThumb.setColorFilter(cf); 255 } 256 } 257 258 @Override 259 public int getOpacity() { 260 return PixelFormat.TRANSLUCENT; 261 } 262 263 @Override 264 public String toString() { 265 return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset + 266 " extent=" + mExtent + (mVertical ? " V" : " H"); 267 } 268 } 269 270 271