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