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