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
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.appcompat.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;
233de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport android.util.AttributeSet;
243de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport android.widget.SeekBar;
253de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikas
26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
273de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.appcompat.R;
28ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.graphics.drawable.DrawableCompat;
29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat;
3010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesclass AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
3210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
3310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    private final SeekBar mView;
3410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
35b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private Drawable mTickMark;
36b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private ColorStateList mTickMarkTintList = null;
37b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private PorterDuff.Mode mTickMarkTintMode = null;
38b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private boolean mHasTickMarkTint = false;
39b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private boolean mHasTickMarkTintMode = false;
40b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
414c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes    AppCompatSeekBarHelper(SeekBar view) {
424c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes        super(view);
4310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        mView = view;
4410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
4510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
46dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas    @Override
4710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
4810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        super.loadFromAttributes(attrs, defStyleAttr);
4910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes
5010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
51b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                R.styleable.AppCompatSeekBar, defStyleAttr, 0);
52b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb);
5310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        if (drawable != null) {
5410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes            mView.setThumb(drawable);
5510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        }
56b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
57b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark);
58b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        setTickMark(tickMark);
59b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
60b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) {
61b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt(
62b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
63b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mHasTickMarkTintMode = true;
64b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
65b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
66b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) {
67b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint);
68b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mHasTickMarkTint = true;
69b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
70b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
7110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes        a.recycle();
72b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
73b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
74b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
75b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
76b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMark(@Nullable Drawable tickMark) {
77b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
78b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMark.setCallback(null);
79b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
80b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
81b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMark = tickMark;
82b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
83b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (tickMark != null) {
84b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            tickMark.setCallback(mView);
85b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView));
86b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (tickMark.isStateful()) {
87b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                tickMark.setState(mView.getDrawableState());
88b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
89b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            applyTickMarkTint();
90b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
91b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
92b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mView.invalidate();
93b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
94b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
95b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
96b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    Drawable getTickMark() {
97b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMark;
98b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
99b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
100b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMarkTintList(@Nullable ColorStateList tint) {
101b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMarkTintList = tint;
102b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mHasTickMarkTint = true;
103b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
104b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
105b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
106b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
107b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
108b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    ColorStateList getTickMarkTintList() {
109b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMarkTintList;
11010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes    }
111b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
112b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
113b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mTickMarkTintMode = tintMode;
114b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        mHasTickMarkTintMode = true;
115b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
116b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        applyTickMarkTint();
117b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
118b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
119b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    @Nullable
120b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    PorterDuff.Mode getTickMarkTintMode() {
121b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        return mTickMarkTintMode;
122b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
123b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
124b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    private void applyTickMarkTint() {
125b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
126168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes            mTickMark = DrawableCompat.wrap(mTickMark.mutate());
127b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
128b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mHasTickMarkTint) {
129168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes                DrawableCompat.setTintList(mTickMark, mTickMarkTintList);
130b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
131b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
132b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mHasTickMarkTintMode) {
133168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes                DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode);
134b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
135b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
136b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            // The drawable (or one of its children) may not have been
137b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            // stateful before applying the tint, so let's try again.
138b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (mTickMark.isStateful()) {
139b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                mTickMark.setState(mView.getDrawableState());
140b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
141b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
142b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
143b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
144b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void jumpDrawablesToCurrentState() {
145b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
146b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mTickMark.jumpToCurrentState();
147b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
148b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
149b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
150b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void drawableStateChanged() {
151b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        final Drawable tickMark = mTickMark;
152b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (tickMark != null && tickMark.isStateful()
153b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                && tickMark.setState(mView.getDrawableState())) {
154b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            mView.invalidateDrawable(tickMark);
155b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
156b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
157b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
158b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    /**
159b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes     * Draw the tick marks.
160b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes     */
161b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    void drawTickMarks(Canvas canvas) {
162b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        if (mTickMark != null) {
163b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            final int count = mView.getMax();
164b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            if (count > 1) {
165b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int w = mTickMark.getIntrinsicWidth();
166b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int h = mTickMark.getIntrinsicHeight();
167b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int halfW = w >= 0 ? w / 2 : 1;
168b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int halfH = h >= 0 ? h / 2 : 1;
169b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
170b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
171b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final float spacing = (mView.getWidth() - mView.getPaddingLeft()
172b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                        - mView.getPaddingRight()) / (float) count;
173b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                final int saveCount = canvas.save();
174b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2);
175b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                for (int i = 0; i <= count; i++) {
176b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    mTickMark.draw(canvas);
177b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                    canvas.translate(spacing, 0);
178b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                }
179b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes                canvas.restoreToCount(saveCount);
180b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes            }
181b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes        }
182b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes    }
183b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes
18410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes}
185