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 5package org.chromium.ui; 6 7import android.content.Context; 8import android.graphics.Color; 9import android.util.AttributeSet; 10import android.view.LayoutInflater; 11import android.view.View; 12import android.view.accessibility.AccessibilityEvent; 13import android.widget.LinearLayout; 14import android.widget.SeekBar; 15import 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 */ 21public 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} 253