1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.ui; |
6 | |
7 | import android.content.Context; |
8 | import android.graphics.Color; |
9 | import android.util.AttributeSet; |
10 | import android.view.LayoutInflater; |
11 | import android.view.View; |
12 | import android.view.accessibility.AccessibilityEvent; |
13 | import android.widget.LinearLayout; |
14 | import android.widget.SeekBar; |
15 | import android.widget.SeekBar.OnSeekBarChangeListener; |
16 | |
17 | /** |
18 | * Represents a more advanced way for the user to choose a color, based on selecting each of |
19 | * the Hue, Saturation and Value attributes. |
20 | */ |
21 | public class ColorPickerAdvanced extends LinearLayout implements OnSeekBarChangeListener { |
22 | private static final int HUE_SEEK_BAR_MAX = 360; |
23 | |
24 | private static final int HUE_COLOR_COUNT = 7; |
25 | |
26 | private static final int SATURATION_SEEK_BAR_MAX = 100; |
27 | |
28 | private static final int SATURATION_COLOR_COUNT = 2; |
29 | |
30 | private static final int VALUE_SEEK_BAR_MAX = 100; |
31 | |
32 | private static final int VALUE_COLOR_COUNT = 2; |
33 | |
34 | ColorPickerAdvancedComponent mHueDetails; |
35 | |
36 | ColorPickerAdvancedComponent mSaturationDetails; |
37 | |
38 | ColorPickerAdvancedComponent mValueDetails; |
39 | |
40 | private OnColorChangedListener mOnColorChangedListener; |
41 | |
42 | private int mCurrentColor; |
43 | |
44 | private final float[] mCurrentHsvValues = new float[3]; |
45 | |
46 | public ColorPickerAdvanced(Context context, AttributeSet attrs) { |
47 | super(context, attrs); |
48 | init(); |
49 | } |
50 | |
51 | public ColorPickerAdvanced(Context context, AttributeSet attrs, int defStyle) { |
52 | super(context, attrs, defStyle); |
53 | init(); |
54 | } |
55 | |
56 | public ColorPickerAdvanced(Context context) { |
57 | super(context); |
58 | init(); |
59 | } |
60 | |
61 | /** |
62 | * Initializes all the views and variables in the advanced view. |
63 | */ |
64 | private void init() { |
65 | setOrientation(LinearLayout.VERTICAL); |
66 | |
67 | mHueDetails = createAndAddNewGradient(R.string.color_picker_hue, |
68 | HUE_SEEK_BAR_MAX, this); |
69 | mSaturationDetails = createAndAddNewGradient(R.string.color_picker_saturation, |
70 | SATURATION_SEEK_BAR_MAX, this); |
71 | mValueDetails = createAndAddNewGradient(R.string.color_picker_value, |
72 | VALUE_SEEK_BAR_MAX, this); |
73 | |
74 | refreshGradientComponents(); |
75 | } |
76 | |
77 | /** |
78 | * Creates a new GradientDetails object from the parameters provided, initializes it, |
79 | * and adds it to this advanced view. |
80 | * |
81 | * @param textResourceId The text to display for the label. |
82 | * @param seekBarMax The maximum value of the seek bar for the gradient. |
83 | * @param seekBarListener Object listening to when the user changes the seek bar. |
84 | * |
85 | * @return A new GradientDetails object initialized with the given parameters. |
86 | */ |
87 | public ColorPickerAdvancedComponent createAndAddNewGradient(int textResourceId, |
88 | int seekBarMax, |
89 | OnSeekBarChangeListener seekBarListener) { |
90 | LayoutInflater inflater = (LayoutInflater) getContext() |
91 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
92 | View newComponent = inflater.inflate(R.layout.color_picker_advanced_component, null); |
93 | addView(newComponent); |
94 | |
95 | return new ColorPickerAdvancedComponent(newComponent, |
96 | textResourceId, |
97 | seekBarMax, |
98 | seekBarListener); |
99 | } |
100 | |
101 | /** |
102 | * Sets the listener for when the user changes the color. |
103 | * |
104 | * @param onColorChangedListener The object listening for the change in color. |
105 | */ |
106 | public void setListener(OnColorChangedListener onColorChangedListener) { |
107 | mOnColorChangedListener = onColorChangedListener; |
108 | } |
109 | |
110 | /** |
111 | * @return The color the user has currently chosen. |
112 | */ |
113 | public int getColor() { |
114 | return mCurrentColor; |
115 | } |
116 | |
117 | /** |
118 | * Sets the color that the user has currently chosen. |
119 | * |
120 | * @param color The currently chosen color. |
121 | */ |
122 | public void setColor(int color) { |
123 | mCurrentColor = color; |
124 | Color.colorToHSV(mCurrentColor, mCurrentHsvValues); |
125 | refreshGradientComponents(); |
126 | } |
127 | |
128 | /** |
129 | * Notifies the listener, if there is one, of a change in the selected color. |
130 | */ |
131 | private void notifyColorChanged() { |
132 | if (mOnColorChangedListener != null) { |
133 | mOnColorChangedListener.onColorChanged(getColor()); |
134 | } |
135 | } |
136 | |
137 | /** |
138 | * Callback for when a slider is updated on the advanced view. |
139 | * |
140 | * @param seekBar The color slider that was updated. |
141 | * @param progress The new value of the color slider. |
142 | * @param fromUser Whether it was the user the changed the value, or whether |
143 | * we were setting it up. |
144 | */ |
145 | @Override |
146 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { |
147 | if (fromUser) { |
148 | mCurrentHsvValues[0] = mHueDetails.getValue(); |
149 | mCurrentHsvValues[1] = mSaturationDetails.getValue() / 100.0f; |
150 | mCurrentHsvValues[2] = mValueDetails.getValue() / 100.0f; |
151 | |
152 | mCurrentColor = Color.HSVToColor(mCurrentHsvValues); |
153 | |
154 | updateHueGradient(); |
155 | updateSaturationGradient(); |
156 | updateValueGradient(); |
157 | |
158 | notifyColorChanged(); |
159 | } |
160 | } |
161 | |
162 | /** |
163 | * Updates only the hue gradient display with the hue value for the |
164 | * currently selected color. |
165 | */ |
166 | private void updateHueGradient() { |
167 | float[] tempHsvValues = new float[3]; |
168 | tempHsvValues[1] = mCurrentHsvValues[1]; |
169 | tempHsvValues[2] = mCurrentHsvValues[2]; |
170 | |
171 | int[] newColors = new int[HUE_COLOR_COUNT]; |
172 | |
173 | for (int i = 0; i < HUE_COLOR_COUNT; ++i) { |
174 | tempHsvValues[0] = i * 60.0f; |
175 | newColors[i] = Color.HSVToColor(tempHsvValues); |
176 | } |
177 | mHueDetails.setGradientColors(newColors); |
178 | } |
179 | |
180 | /** |
181 | * Updates only the saturation gradient display with the saturation value |
182 | * for the currently selected color. |
183 | */ |
184 | private void updateSaturationGradient() { |
185 | float[] tempHsvValues = new float[3]; |
186 | tempHsvValues[0] = mCurrentHsvValues[0]; |
187 | tempHsvValues[1] = 0.0f; |
188 | tempHsvValues[2] = mCurrentHsvValues[2]; |
189 | |
190 | int[] newColors = new int[SATURATION_COLOR_COUNT]; |
191 | |
192 | newColors[0] = Color.HSVToColor(tempHsvValues); |
193 | |
194 | tempHsvValues[1] = 1.0f; |
195 | newColors[1] = Color.HSVToColor(tempHsvValues); |
196 | mSaturationDetails.setGradientColors(newColors); |
197 | } |
198 | |
199 | /** |
200 | * Updates only the Value gradient display with the Value amount for |
201 | * the currently selected color. |
202 | */ |
203 | private void updateValueGradient() { |
204 | float[] tempHsvValues = new float[3]; |
205 | tempHsvValues[0] = mCurrentHsvValues[0]; |
206 | tempHsvValues[1] = mCurrentHsvValues[1]; |
207 | tempHsvValues[2] = 0.0f; |
208 | |
209 | int[] newColors = new int[VALUE_COLOR_COUNT]; |
210 | |
211 | newColors[0] = Color.HSVToColor(tempHsvValues); |
212 | |
213 | tempHsvValues[2] = 1.0f; |
214 | newColors[1] = Color.HSVToColor(tempHsvValues); |
215 | mValueDetails.setGradientColors(newColors); |
216 | } |
217 | |
218 | /** |
219 | * Updates all the gradient displays to show the currently selected color. |
220 | */ |
221 | private void refreshGradientComponents() { |
222 | // Round and bound the saturation value. |
223 | int saturationValue = Math.round(mCurrentHsvValues[1] * 100.0f); |
224 | saturationValue = Math.min(saturationValue, SATURATION_SEEK_BAR_MAX); |
225 | saturationValue = Math.max(saturationValue, 0); |
226 | |
227 | // Round and bound the Value amount. |
228 | int valueValue = Math.round(mCurrentHsvValues[2] * 100.0f); |
229 | valueValue = Math.min(valueValue, VALUE_SEEK_BAR_MAX); |
230 | valueValue = Math.max(valueValue, 0); |
231 | |
232 | // Don't need to round the hue value since its possible values match the seek bar |
233 | // range directly. |
234 | mHueDetails.setValue(mCurrentHsvValues[0]); |
235 | mSaturationDetails.setValue(saturationValue); |
236 | mValueDetails.setValue(valueValue); |
237 | |
238 | updateHueGradient(); |
239 | updateSaturationGradient(); |
240 | updateValueGradient(); |
241 | } |
242 | |
243 | @Override |
244 | public void onStartTrackingTouch(SeekBar seekBar) { |
245 | // Do nothing. |
246 | } |
247 | |
248 | @Override |
249 | public void onStopTrackingTouch(SeekBar seekBar) { |
250 | // Do nothing. |
251 | } |
252 | } |