1/*
2 * Copyright (C) 2015 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.support.v7.widget;
18
19import android.content.res.ColorStateList;
20import android.graphics.Canvas;
21import android.graphics.PorterDuff;
22import android.graphics.drawable.Drawable;
23import android.support.annotation.Nullable;
24import android.support.annotation.RequiresApi;
25import android.support.v4.graphics.drawable.DrawableCompat;
26import android.support.v4.view.ViewCompat;
27import android.support.v7.appcompat.R;
28import android.util.AttributeSet;
29import android.widget.SeekBar;
30
31class AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
32
33    private final SeekBar mView;
34
35    private Drawable mTickMark;
36    private ColorStateList mTickMarkTintList = null;
37    private PorterDuff.Mode mTickMarkTintMode = null;
38    private boolean mHasTickMarkTint = false;
39    private boolean mHasTickMarkTintMode = false;
40
41    AppCompatSeekBarHelper(SeekBar view) {
42        super(view);
43        mView = view;
44    }
45
46    @Override
47    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
48        super.loadFromAttributes(attrs, defStyleAttr);
49
50        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
51                R.styleable.AppCompatSeekBar, defStyleAttr, 0);
52        final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb);
53        if (drawable != null) {
54            mView.setThumb(drawable);
55        }
56
57        final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark);
58        setTickMark(tickMark);
59
60        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) {
61            mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt(
62                    R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
63            mHasTickMarkTintMode = true;
64        }
65
66        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) {
67            mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint);
68            mHasTickMarkTint = true;
69        }
70
71        a.recycle();
72
73        applyTickMarkTint();
74    }
75
76    void setTickMark(@Nullable Drawable tickMark) {
77        if (mTickMark != null) {
78            mTickMark.setCallback(null);
79        }
80
81        mTickMark = tickMark;
82
83        if (tickMark != null) {
84            tickMark.setCallback(mView);
85            DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView));
86            if (tickMark.isStateful()) {
87                tickMark.setState(mView.getDrawableState());
88            }
89            applyTickMarkTint();
90        }
91
92        mView.invalidate();
93    }
94
95    @Nullable
96    Drawable getTickMark() {
97        return mTickMark;
98    }
99
100    void setTickMarkTintList(@Nullable ColorStateList tint) {
101        mTickMarkTintList = tint;
102        mHasTickMarkTint = true;
103
104        applyTickMarkTint();
105    }
106
107    @Nullable
108    ColorStateList getTickMarkTintList() {
109        return mTickMarkTintList;
110    }
111
112    void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
113        mTickMarkTintMode = tintMode;
114        mHasTickMarkTintMode = true;
115
116        applyTickMarkTint();
117    }
118
119    @Nullable
120    PorterDuff.Mode getTickMarkTintMode() {
121        return mTickMarkTintMode;
122    }
123
124    private void applyTickMarkTint() {
125        if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
126            mTickMark = DrawableCompat.wrap(mTickMark.mutate());
127
128            if (mHasTickMarkTint) {
129                DrawableCompat.setTintList(mTickMark, mTickMarkTintList);
130            }
131
132            if (mHasTickMarkTintMode) {
133                DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode);
134            }
135
136            // The drawable (or one of its children) may not have been
137            // stateful before applying the tint, so let's try again.
138            if (mTickMark.isStateful()) {
139                mTickMark.setState(mView.getDrawableState());
140            }
141        }
142    }
143
144    @RequiresApi(11)
145    void jumpDrawablesToCurrentState() {
146        if (mTickMark != null) {
147            mTickMark.jumpToCurrentState();
148        }
149    }
150
151    void drawableStateChanged() {
152        final Drawable tickMark = mTickMark;
153        if (tickMark != null && tickMark.isStateful()
154                && tickMark.setState(mView.getDrawableState())) {
155            mView.invalidateDrawable(tickMark);
156        }
157    }
158
159    /**
160     * Draw the tick marks.
161     */
162    void drawTickMarks(Canvas canvas) {
163        if (mTickMark != null) {
164            final int count = mView.getMax();
165            if (count > 1) {
166                final int w = mTickMark.getIntrinsicWidth();
167                final int h = mTickMark.getIntrinsicHeight();
168                final int halfW = w >= 0 ? w / 2 : 1;
169                final int halfH = h >= 0 ? h / 2 : 1;
170                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
171
172                final float spacing = (mView.getWidth() - mView.getPaddingLeft()
173                        - mView.getPaddingRight()) / (float) count;
174                final int saveCount = canvas.save();
175                canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2);
176                for (int i = 0; i <= count; i++) {
177                    mTickMark.draw(canvas);
178                    canvas.translate(spacing, 0);
179                }
180                canvas.restoreToCount(saveCount);
181            }
182        }
183    }
184
185}
186