ScrollBarDrawable.java revision f8512ce08174426dfbba96e8108e5a64332f1e71
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.widget;
18
19import android.graphics.Canvas;
20import android.graphics.ColorFilter;
21import android.graphics.PixelFormat;
22import android.graphics.Rect;
23import 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 */
31public class ScrollBarDrawable extends Drawable {
32    private static final int[] STATE_ENABLED = new int[] { android.R.attr.state_enabled };
33
34    private Drawable mVerticalTrack;
35    private Drawable mHorizontalTrack;
36    private Drawable mVerticalThumb;
37    private Drawable mHorizontalThumb;
38    private int mRange;
39    private int mOffset;
40    private int mExtent;
41    private boolean mVertical;
42    private boolean mChanged;
43    private boolean mRangeChanged;
44    private final Rect mTempBounds = new Rect();
45    private boolean mAlwaysDrawHorizontalTrack;
46    private boolean mAlwaysDrawVerticalTrack;
47    private boolean mMutated;
48
49    public ScrollBarDrawable() {
50    }
51
52    /**
53     * Indicate whether the horizontal scrollbar track should always be drawn regardless of the
54     * extent. Defaults to false.
55     *
56     * @param alwaysDrawTrack Set to true if the track should always be drawn
57     */
58    public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) {
59        mAlwaysDrawHorizontalTrack = alwaysDrawTrack;
60    }
61
62    /**
63     * Indicate whether the vertical scrollbar track should always be drawn regardless of the
64     * extent. Defaults to false.
65     *
66     * @param alwaysDrawTrack Set to true if the track should always be drawn
67     */
68    public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) {
69        mAlwaysDrawVerticalTrack = alwaysDrawTrack;
70    }
71
72    /**
73     * Indicates whether the vertical scrollbar track should always be drawn regardless of the
74     * extent.
75     */
76    public boolean getAlwaysDrawVerticalTrack() {
77        return mAlwaysDrawVerticalTrack;
78    }
79
80    /**
81     * Indicates whether the horizontal scrollbar track should always be drawn regardless of the
82     * extent.
83     */
84    public boolean getAlwaysDrawHorizontalTrack() {
85        return mAlwaysDrawHorizontalTrack;
86    }
87
88    public void setParameters(int range, int offset, int extent, boolean vertical) {
89        if (mVertical != vertical) {
90            mChanged = true;
91        }
92
93        if (mRange != range || mOffset != offset || mExtent != extent) {
94            mRangeChanged = true;
95        }
96
97        mRange = range;
98        mOffset = offset;
99        mExtent = extent;
100        mVertical = vertical;
101    }
102
103    @Override
104    public void draw(Canvas canvas) {
105        final boolean vertical = mVertical;
106        final int extent = mExtent;
107        final int range = mRange;
108
109        boolean drawTrack = true;
110        boolean drawThumb = true;
111        if (extent <= 0 || range <= extent) {
112            drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack;
113            drawThumb = false;
114        }
115
116        Rect r = getBounds();
117        if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) {
118            return;
119        }
120        if (drawTrack) {
121            drawTrack(canvas, r, vertical);
122        }
123
124        if (drawThumb) {
125            int size = vertical ? r.height() : r.width();
126            int thickness = vertical ? r.width() : r.height();
127            int length = Math.round((float) size * extent / range);
128            int offset = Math.round((float) (size - length) * mOffset / (range - extent));
129
130            // avoid the tiny thumb
131            int minLength = thickness * 2;
132            if (length < minLength) {
133                length = minLength;
134            }
135            // avoid the too-big thumb
136            if (offset + length > size) {
137                offset = size - length;
138            }
139
140            drawThumb(canvas, r, offset, length, vertical);
141        }
142    }
143
144    @Override
145    protected void onBoundsChange(Rect bounds) {
146        super.onBoundsChange(bounds);
147        mChanged = true;
148    }
149
150    protected void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
151        Drawable track;
152        if (vertical) {
153            track = mVerticalTrack;
154        } else {
155            track = mHorizontalTrack;
156        }
157        if (track != null) {
158            if (mChanged) {
159                track.setBounds(bounds);
160            }
161            track.draw(canvas);
162        }
163    }
164
165    protected void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
166        final Rect thumbRect = mTempBounds;
167        final boolean changed = mRangeChanged || mChanged;
168        if (changed) {
169            if (vertical) {
170                thumbRect.set(bounds.left,  bounds.top + offset,
171                        bounds.right, bounds.top + offset + length);
172            } else {
173                thumbRect.set(bounds.left + offset, bounds.top,
174                        bounds.left + offset + length, bounds.bottom);
175            }
176        }
177
178        if (vertical) {
179            if (mVerticalThumb != null) {
180                final Drawable thumb = mVerticalThumb;
181                if (changed) thumb.setBounds(thumbRect);
182                thumb.draw(canvas);
183            }
184        } else {
185            if (mHorizontalThumb != null) {
186                final Drawable thumb = mHorizontalThumb;
187                if (changed) thumb.setBounds(thumbRect);
188                thumb.draw(canvas);
189            }
190        }
191    }
192
193    public void setVerticalThumbDrawable(Drawable thumb) {
194        if (thumb != null) {
195            if (mMutated) {
196                thumb.mutate();
197            }
198            thumb.setState(STATE_ENABLED);
199            mVerticalThumb = thumb;
200        }
201    }
202
203    public void setVerticalTrackDrawable(Drawable track) {
204        if (track != null) {
205            if (mMutated) {
206                track.mutate();
207            }
208            track.setState(STATE_ENABLED);
209        }
210        mVerticalTrack = track;
211    }
212
213    public void setHorizontalThumbDrawable(Drawable thumb) {
214        if (thumb != null) {
215            if (mMutated) {
216                thumb.mutate();
217            }
218            thumb.setState(STATE_ENABLED);
219            mHorizontalThumb = thumb;
220        }
221    }
222
223    public void setHorizontalTrackDrawable(Drawable track) {
224        if (track != null) {
225            if (mMutated) {
226                track.mutate();
227            }
228            track.setState(STATE_ENABLED);
229        }
230        mHorizontalTrack = track;
231    }
232
233    public int getSize(boolean vertical) {
234        if (vertical) {
235            return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() :
236                    mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0;
237        } else {
238            return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() :
239                    mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0;
240        }
241    }
242
243    @Override
244    public ScrollBarDrawable mutate() {
245        if (!mMutated && super.mutate() == this) {
246            if (mVerticalTrack != null) {
247                mVerticalTrack.mutate();
248            }
249            if (mVerticalThumb != null) {
250                mVerticalThumb.mutate();
251            }
252            if (mHorizontalTrack != null) {
253                mHorizontalTrack.mutate();
254            }
255            if (mHorizontalThumb != null) {
256                mHorizontalThumb.mutate();
257            }
258            mMutated = true;
259        }
260        return this;
261    }
262
263    @Override
264    public void setAlpha(int alpha) {
265        if (mVerticalTrack != null) {
266            mVerticalTrack.setAlpha(alpha);
267        }
268        if (mVerticalThumb != null) {
269            mVerticalThumb.setAlpha(alpha);
270        }
271        if (mHorizontalTrack != null) {
272            mHorizontalTrack.setAlpha(alpha);
273        }
274        if (mHorizontalThumb != null) {
275            mHorizontalThumb.setAlpha(alpha);
276        }
277    }
278
279    @Override
280    public int getAlpha() {
281        // All elements should have same alpha, just return one of them
282        return mVerticalThumb.getAlpha();
283    }
284
285    @Override
286    public void setColorFilter(ColorFilter cf) {
287        if (mVerticalTrack != null) {
288            mVerticalTrack.setColorFilter(cf);
289        }
290        if (mVerticalThumb != null) {
291            mVerticalThumb.setColorFilter(cf);
292        }
293        if (mHorizontalTrack != null) {
294            mHorizontalTrack.setColorFilter(cf);
295        }
296        if (mHorizontalThumb != null) {
297            mHorizontalThumb.setColorFilter(cf);
298        }
299    }
300
301    @Override
302    public int getOpacity() {
303        return PixelFormat.TRANSLUCENT;
304    }
305
306    @Override
307    public String toString() {
308        return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset +
309               " extent=" + mExtent + (mVertical ? " V" : " H");
310    }
311}
312
313
314