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.annotation.NonNull;
     20 import android.graphics.Canvas;
     21 import android.graphics.ColorFilter;
     22 import android.graphics.PixelFormat;
     23 import android.graphics.Rect;
     24 import android.graphics.drawable.Drawable;
     25 
     26 import com.android.internal.widget.ScrollBarUtils;
     27 
     28 /**
     29  * This is only used by View for displaying its scroll bars. It should probably
     30  * be moved in to the view package since it is used in that lower-level layer.
     31  * For now, we'll hide it so it can be cleaned up later.
     32  *
     33  * {@hide}
     34  */
     35 public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
     36     private Drawable mVerticalTrack;
     37     private Drawable mHorizontalTrack;
     38     private Drawable mVerticalThumb;
     39     private Drawable mHorizontalThumb;
     40 
     41     private int mRange;
     42     private int mOffset;
     43     private int mExtent;
     44 
     45     private boolean mVertical;
     46     private boolean mBoundsChanged;
     47     private boolean mRangeChanged;
     48     private boolean mAlwaysDrawHorizontalTrack;
     49     private boolean mAlwaysDrawVerticalTrack;
     50     private boolean mMutated;
     51 
     52     private int mAlpha = 255;
     53     private boolean mHasSetAlpha;
     54 
     55     private ColorFilter mColorFilter;
     56     private boolean mHasSetColorFilter;
     57 
     58     /**
     59      * Indicate whether the horizontal scrollbar track should always be drawn
     60      * regardless of the extent. Defaults to false.
     61      *
     62      * @param alwaysDrawTrack Whether the track should always be drawn
     63      *
     64      * @see #getAlwaysDrawHorizontalTrack()
     65      */
     66     public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) {
     67         mAlwaysDrawHorizontalTrack = alwaysDrawTrack;
     68     }
     69 
     70     /**
     71      * Indicate whether the vertical scrollbar track should always be drawn
     72      * regardless of the extent. Defaults to false.
     73      *
     74      * @param alwaysDrawTrack Whether the track should always be drawn
     75      *
     76      * @see #getAlwaysDrawVerticalTrack()
     77      */
     78     public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) {
     79         mAlwaysDrawVerticalTrack = alwaysDrawTrack;
     80     }
     81 
     82     /**
     83      * @return whether the vertical scrollbar track should always be drawn
     84      *         regardless of the extent.
     85      *
     86      * @see #setAlwaysDrawVerticalTrack(boolean)
     87      */
     88     public boolean getAlwaysDrawVerticalTrack() {
     89         return mAlwaysDrawVerticalTrack;
     90     }
     91 
     92     /**
     93      * @return whether the horizontal scrollbar track should always be drawn
     94      *         regardless of the extent.
     95      *
     96      * @see #setAlwaysDrawHorizontalTrack(boolean)
     97      */
     98     public boolean getAlwaysDrawHorizontalTrack() {
     99         return mAlwaysDrawHorizontalTrack;
    100     }
    101 
    102     public void setParameters(int range, int offset, int extent, boolean vertical) {
    103         if (mVertical != vertical) {
    104             mVertical = vertical;
    105 
    106             mBoundsChanged = true;
    107         }
    108 
    109         if (mRange != range || mOffset != offset || mExtent != extent) {
    110             mRange = range;
    111             mOffset = offset;
    112             mExtent = extent;
    113 
    114             mRangeChanged = true;
    115         }
    116     }
    117 
    118     @Override
    119     public void draw(Canvas canvas) {
    120         final boolean vertical = mVertical;
    121         final int extent = mExtent;
    122         final int range = mRange;
    123 
    124         boolean drawTrack = true;
    125         boolean drawThumb = true;
    126         if (extent <= 0 || range <= extent) {
    127             drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack;
    128             drawThumb = false;
    129         }
    130 
    131         final Rect r = getBounds();
    132         if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) {
    133             return;
    134         }
    135 
    136         if (drawTrack) {
    137             drawTrack(canvas, r, vertical);
    138         }
    139 
    140         if (drawThumb) {
    141             final int scrollBarLength = vertical ? r.height() : r.width();
    142             final int thickness = vertical ? r.width() : r.height();
    143             final int thumbLength =
    144                     ScrollBarUtils.getThumbLength(scrollBarLength, thickness, extent, range);
    145             final int thumbOffset =
    146                     ScrollBarUtils.getThumbOffset(scrollBarLength, thumbLength, extent, range,
    147                             mOffset);
    148 
    149             drawThumb(canvas, r, thumbOffset, thumbLength, vertical);
    150         }
    151     }
    152 
    153     @Override
    154     protected void onBoundsChange(Rect bounds) {
    155         super.onBoundsChange(bounds);
    156         mBoundsChanged = true;
    157     }
    158 
    159     @Override
    160     public boolean isStateful() {
    161         return (mVerticalTrack != null && mVerticalTrack.isStateful())
    162                 || (mVerticalThumb != null && mVerticalThumb.isStateful())
    163                 || (mHorizontalTrack != null && mHorizontalTrack.isStateful())
    164                 || (mHorizontalThumb != null && mHorizontalThumb.isStateful())
    165                 || super.isStateful();
    166     }
    167 
    168     @Override
    169     protected boolean onStateChange(int[] state) {
    170         boolean changed = super.onStateChange(state);
    171         if (mVerticalTrack != null) {
    172             changed |= mVerticalTrack.setState(state);
    173         }
    174         if (mVerticalThumb != null) {
    175             changed |= mVerticalThumb.setState(state);
    176         }
    177         if (mHorizontalTrack != null) {
    178             changed |= mHorizontalTrack.setState(state);
    179         }
    180         if (mHorizontalThumb != null) {
    181             changed |= mHorizontalThumb.setState(state);
    182         }
    183         return changed;
    184     }
    185 
    186     private void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
    187         final Drawable track;
    188         if (vertical) {
    189             track = mVerticalTrack;
    190         } else {
    191             track = mHorizontalTrack;
    192         }
    193 
    194         if (track != null) {
    195             if (mBoundsChanged) {
    196                 track.setBounds(bounds);
    197             }
    198             track.draw(canvas);
    199         }
    200     }
    201 
    202     private void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
    203         final boolean changed = mRangeChanged || mBoundsChanged;
    204         if (vertical) {
    205             if (mVerticalThumb != null) {
    206                 final Drawable thumb = mVerticalThumb;
    207                 if (changed) {
    208                     thumb.setBounds(bounds.left, bounds.top + offset,
    209                             bounds.right, bounds.top + offset + length);
    210                 }
    211 
    212                 thumb.draw(canvas);
    213             }
    214         } else {
    215             if (mHorizontalThumb != null) {
    216                 final Drawable thumb = mHorizontalThumb;
    217                 if (changed) {
    218                     thumb.setBounds(bounds.left + offset, bounds.top,
    219                             bounds.left + offset + length, bounds.bottom);
    220                 }
    221 
    222                 thumb.draw(canvas);
    223             }
    224         }
    225     }
    226 
    227     public void setVerticalThumbDrawable(Drawable thumb) {
    228         if (mVerticalThumb != null) {
    229             mVerticalThumb.setCallback(null);
    230         }
    231 
    232         propagateCurrentState(thumb);
    233         mVerticalThumb = thumb;
    234     }
    235 
    236     public void setVerticalTrackDrawable(Drawable track) {
    237         if (mVerticalTrack != null) {
    238             mVerticalTrack.setCallback(null);
    239         }
    240 
    241         propagateCurrentState(track);
    242         mVerticalTrack = track;
    243     }
    244 
    245     public void setHorizontalThumbDrawable(Drawable thumb) {
    246         if (mHorizontalThumb != null) {
    247             mHorizontalThumb.setCallback(null);
    248         }
    249 
    250         propagateCurrentState(thumb);
    251         mHorizontalThumb = thumb;
    252     }
    253 
    254     public void setHorizontalTrackDrawable(Drawable track) {
    255         if (mHorizontalTrack != null) {
    256             mHorizontalTrack.setCallback(null);
    257         }
    258 
    259         propagateCurrentState(track);
    260         mHorizontalTrack = track;
    261     }
    262 
    263     private void propagateCurrentState(Drawable d) {
    264         if (d != null) {
    265             if (mMutated) {
    266                 d.mutate();
    267             }
    268 
    269             d.setState(getState());
    270             d.setCallback(this);
    271 
    272             if (mHasSetAlpha) {
    273                 d.setAlpha(mAlpha);
    274             }
    275 
    276             if (mHasSetColorFilter) {
    277                 d.setColorFilter(mColorFilter);
    278             }
    279         }
    280     }
    281 
    282     public int getSize(boolean vertical) {
    283         if (vertical) {
    284             return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() :
    285                     mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0;
    286         } else {
    287             return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() :
    288                     mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0;
    289         }
    290     }
    291 
    292     @Override
    293     public ScrollBarDrawable mutate() {
    294         if (!mMutated && super.mutate() == this) {
    295             if (mVerticalTrack != null) {
    296                 mVerticalTrack.mutate();
    297             }
    298             if (mVerticalThumb != null) {
    299                 mVerticalThumb.mutate();
    300             }
    301             if (mHorizontalTrack != null) {
    302                 mHorizontalTrack.mutate();
    303             }
    304             if (mHorizontalThumb != null) {
    305                 mHorizontalThumb.mutate();
    306             }
    307             mMutated = true;
    308         }
    309         return this;
    310     }
    311 
    312     @Override
    313     public void setAlpha(int alpha) {
    314         mAlpha = alpha;
    315         mHasSetAlpha = true;
    316 
    317         if (mVerticalTrack != null) {
    318             mVerticalTrack.setAlpha(alpha);
    319         }
    320         if (mVerticalThumb != null) {
    321             mVerticalThumb.setAlpha(alpha);
    322         }
    323         if (mHorizontalTrack != null) {
    324             mHorizontalTrack.setAlpha(alpha);
    325         }
    326         if (mHorizontalThumb != null) {
    327             mHorizontalThumb.setAlpha(alpha);
    328         }
    329     }
    330 
    331     @Override
    332     public int getAlpha() {
    333         return mAlpha;
    334     }
    335 
    336     @Override
    337     public void setColorFilter(ColorFilter colorFilter) {
    338         mColorFilter = colorFilter;
    339         mHasSetColorFilter = true;
    340 
    341         if (mVerticalTrack != null) {
    342             mVerticalTrack.setColorFilter(colorFilter);
    343         }
    344         if (mVerticalThumb != null) {
    345             mVerticalThumb.setColorFilter(colorFilter);
    346         }
    347         if (mHorizontalTrack != null) {
    348             mHorizontalTrack.setColorFilter(colorFilter);
    349         }
    350         if (mHorizontalThumb != null) {
    351             mHorizontalThumb.setColorFilter(colorFilter);
    352         }
    353     }
    354 
    355     @Override
    356     public ColorFilter getColorFilter() {
    357         return mColorFilter;
    358     }
    359 
    360     @Override
    361     public int getOpacity() {
    362         return PixelFormat.TRANSLUCENT;
    363     }
    364 
    365     @Override
    366     public void invalidateDrawable(@NonNull Drawable who) {
    367         invalidateSelf();
    368     }
    369 
    370     @Override
    371     public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
    372         scheduleSelf(what, when);
    373     }
    374 
    375     @Override
    376     public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
    377         unscheduleSelf(what);
    378     }
    379 
    380     @Override
    381     public String toString() {
    382         return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset +
    383                " extent=" + mExtent + (mVertical ? " V" : " H");
    384     }
    385 }
    386 
    387 
    388