110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes/*
210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Copyright (C) 2015 The Android Open Source Project
310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * you may not use this file except in compliance with the License.
610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * You may obtain a copy of the License at
710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes *
1010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Unless required by applicable law or agreed to in writing, software
1110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
1210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * See the License for the specific language governing permissions and
1410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * limitations under the License.
1510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes */
1610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
1710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banespackage android.support.v7.widget;
1810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
19b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.content.res.ColorStateList;
20b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.graphics.Canvas;
21b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.graphics.PorterDuff;
2210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.Drawable;
23b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.support.annotation.Nullable;
24b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat;
25b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.support.v4.view.ViewCompat;
26b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.support.v7.appcompat.R;
2710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.util.AttributeSet;
2810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.widget.SeekBar;
2910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesclass AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
3110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private final SeekBar mView;
3310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
34b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private Drawable mTickMark;
35b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private ColorStateList mTickMarkTintList = null;
36b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private PorterDuff.Mode mTickMarkTintMode = null;
37b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private boolean mHasTickMarkTint = false;
38b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private boolean mHasTickMarkTintMode = false;
39b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
404c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes    AppCompatSeekBarHelper(SeekBar view) {
414c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes        super(view);
4210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        mView = view;
4310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
4410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
45dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas    @Override
4610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
4710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        super.loadFromAttributes(attrs, defStyleAttr);
4810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
4910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
50b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                R.styleable.AppCompatSeekBar, defStyleAttr, 0);
51b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb);
5210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable != null) {
5310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            mView.setThumb(drawable);
5410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
55b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
56b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark);
57b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        setTickMark(tickMark);
58b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
59b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) {
60b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt(
61b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
62b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mHasTickMarkTintMode = true;
63b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
64b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
65b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) {
66b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint);
67b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mHasTickMarkTint = true;
68b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
69b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
7010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        a.recycle();
71b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
72b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
73b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
74b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
75b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMark(@Nullable Drawable tickMark) {
76b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
77b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMark.setCallback(null);
78b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
79b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
80b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMark = tickMark;
81b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
82b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (tickMark != null) {
83b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            tickMark.setCallback(mView);
84b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView));
85b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (tickMark.isStateful()) {
86b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                tickMark.setState(mView.getDrawableState());
87b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
88b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            applyTickMarkTint();
89b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
90b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
91b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mView.invalidate();
92b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
93b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
94b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
95b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    Drawable getTickMark() {
96b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMark;
97b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
98b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
99b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMarkTintList(@Nullable ColorStateList tint) {
100b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMarkTintList = tint;
101b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mHasTickMarkTint = true;
102b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
103b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
104b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
105b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
106b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
107b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    ColorStateList getTickMarkTintList() {
108b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMarkTintList;
10910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
110b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
111b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
112b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMarkTintMode = tintMode;
113b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mHasTickMarkTintMode = true;
114b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
115b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
116b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
117b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
118b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
119b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    PorterDuff.Mode getTickMarkTintMode() {
120b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMarkTintMode;
121b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
122b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
123b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private void applyTickMarkTint() {
124b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
125168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes            mTickMark = DrawableCompat.wrap(mTickMark.mutate());
126b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
127b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mHasTickMarkTint) {
128168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes                DrawableCompat.setTintList(mTickMark, mTickMarkTintList);
129b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
130b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
131b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mHasTickMarkTintMode) {
132168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes                DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode);
133b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
134b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
135b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            // The drawable (or one of its children) may not have been
136b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            // stateful before applying the tint, so let's try again.
137b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mTickMark.isStateful()) {
138b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                mTickMark.setState(mView.getDrawableState());
139b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
140b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
141b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
142b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
143b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void jumpDrawablesToCurrentState() {
144b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
145b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMark.jumpToCurrentState();
146b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
147b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
148b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
149b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void drawableStateChanged() {
150b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable tickMark = mTickMark;
151b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (tickMark != null && tickMark.isStateful()
152b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                && tickMark.setState(mView.getDrawableState())) {
153b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mView.invalidateDrawable(tickMark);
154b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
155b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
156b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
157b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    /**
158b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes     * Draw the tick marks.
159b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes     */
160b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void drawTickMarks(Canvas canvas) {
161b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
162b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            final int count = mView.getMax();
163b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (count > 1) {
164b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int w = mTickMark.getIntrinsicWidth();
165b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int h = mTickMark.getIntrinsicHeight();
166b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int halfW = w >= 0 ? w / 2 : 1;
167b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int halfH = h >= 0 ? h / 2 : 1;
168b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
169b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
170b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final float spacing = (mView.getWidth() - mView.getPaddingLeft()
171b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                        - mView.getPaddingRight()) / (float) count;
172b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int saveCount = canvas.save();
173b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2);
174b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                for (int i = 0; i <= count; i++) {
175b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    mTickMark.draw(canvas);
176b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    canvas.translate(spacing, 0);
177b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                }
178b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                canvas.restoreToCount(saveCount);
179b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
180b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
181b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
182b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
18310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes}
184