Home | History | Annotate | Download | only in widget
      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 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