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