Home | History | Annotate | Download | only in ui
      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