Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.apis.graphics;
     18 
     19 import android.os.Bundle;
     20 import android.app.Dialog;
     21 import android.content.Context;
     22 import android.graphics.*;
     23 import android.view.MotionEvent;
     24 import android.view.View;
     25 
     26 public class ColorPickerDialog extends Dialog {
     27 
     28     public interface OnColorChangedListener {
     29         void colorChanged(int color);
     30     }
     31 
     32     private OnColorChangedListener mListener;
     33     private int mInitialColor;
     34 
     35     private static class ColorPickerView extends View {
     36         private Paint mPaint;
     37         private Paint mCenterPaint;
     38         private final int[] mColors;
     39         private OnColorChangedListener mListener;
     40 
     41         ColorPickerView(Context c, OnColorChangedListener l, int color) {
     42             super(c);
     43             mListener = l;
     44             mColors = new int[] {
     45                 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
     46                 0xFFFFFF00, 0xFFFF0000
     47             };
     48             Shader s = new SweepGradient(0, 0, mColors, null);
     49 
     50             mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     51             mPaint.setShader(s);
     52             mPaint.setStyle(Paint.Style.STROKE);
     53             mPaint.setStrokeWidth(32);
     54 
     55             mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     56             mCenterPaint.setColor(color);
     57             mCenterPaint.setStrokeWidth(5);
     58         }
     59 
     60         private boolean mTrackingCenter;
     61         private boolean mHighlightCenter;
     62 
     63         @Override
     64         protected void onDraw(Canvas canvas) {
     65             float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;
     66 
     67             canvas.translate(CENTER_X, CENTER_X);
     68 
     69             canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
     70             canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
     71 
     72             if (mTrackingCenter) {
     73                 int c = mCenterPaint.getColor();
     74                 mCenterPaint.setStyle(Paint.Style.STROKE);
     75 
     76                 if (mHighlightCenter) {
     77                     mCenterPaint.setAlpha(0xFF);
     78                 } else {
     79                     mCenterPaint.setAlpha(0x80);
     80                 }
     81                 canvas.drawCircle(0, 0,
     82                                   CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
     83                                   mCenterPaint);
     84 
     85                 mCenterPaint.setStyle(Paint.Style.FILL);
     86                 mCenterPaint.setColor(c);
     87             }
     88         }
     89 
     90         @Override
     91         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     92             setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
     93         }
     94 
     95         private static final int CENTER_X = 100;
     96         private static final int CENTER_Y = 100;
     97         private static final int CENTER_RADIUS = 32;
     98 
     99         private int floatToByte(float x) {
    100             int n = java.lang.Math.round(x);
    101             return n;
    102         }
    103         private int pinToByte(int n) {
    104             if (n < 0) {
    105                 n = 0;
    106             } else if (n > 255) {
    107                 n = 255;
    108             }
    109             return n;
    110         }
    111 
    112         private int ave(int s, int d, float p) {
    113             return s + java.lang.Math.round(p * (d - s));
    114         }
    115 
    116         private int interpColor(int colors[], float unit) {
    117             if (unit <= 0) {
    118                 return colors[0];
    119             }
    120             if (unit >= 1) {
    121                 return colors[colors.length - 1];
    122             }
    123 
    124             float p = unit * (colors.length - 1);
    125             int i = (int)p;
    126             p -= i;
    127 
    128             // now p is just the fractional part [0...1) and i is the index
    129             int c0 = colors[i];
    130             int c1 = colors[i+1];
    131             int a = ave(Color.alpha(c0), Color.alpha(c1), p);
    132             int r = ave(Color.red(c0), Color.red(c1), p);
    133             int g = ave(Color.green(c0), Color.green(c1), p);
    134             int b = ave(Color.blue(c0), Color.blue(c1), p);
    135 
    136             return Color.argb(a, r, g, b);
    137         }
    138 
    139         private int rotateColor(int color, float rad) {
    140             float deg = rad * 180 / 3.1415927f;
    141             int r = Color.red(color);
    142             int g = Color.green(color);
    143             int b = Color.blue(color);
    144 
    145             ColorMatrix cm = new ColorMatrix();
    146             ColorMatrix tmp = new ColorMatrix();
    147 
    148             cm.setRGB2YUV();
    149             tmp.setRotate(0, deg);
    150             cm.postConcat(tmp);
    151             tmp.setYUV2RGB();
    152             cm.postConcat(tmp);
    153 
    154             final float[] a = cm.getArray();
    155 
    156             int ir = floatToByte(a[0] * r +  a[1] * g +  a[2] * b);
    157             int ig = floatToByte(a[5] * r +  a[6] * g +  a[7] * b);
    158             int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
    159 
    160             return Color.argb(Color.alpha(color), pinToByte(ir),
    161                               pinToByte(ig), pinToByte(ib));
    162         }
    163 
    164         private static final float PI = 3.1415926f;
    165 
    166         @Override
    167         public boolean onTouchEvent(MotionEvent event) {
    168             float x = event.getX() - CENTER_X;
    169             float y = event.getY() - CENTER_Y;
    170             boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
    171 
    172             switch (event.getAction()) {
    173                 case MotionEvent.ACTION_DOWN:
    174                     mTrackingCenter = inCenter;
    175                     if (inCenter) {
    176                         mHighlightCenter = true;
    177                         invalidate();
    178                         break;
    179                     }
    180                 case MotionEvent.ACTION_MOVE:
    181                     if (mTrackingCenter) {
    182                         if (mHighlightCenter != inCenter) {
    183                             mHighlightCenter = inCenter;
    184                             invalidate();
    185                         }
    186                     } else {
    187                         float angle = (float)java.lang.Math.atan2(y, x);
    188                         // need to turn angle [-PI ... PI] into unit [0....1]
    189                         float unit = angle/(2*PI);
    190                         if (unit < 0) {
    191                             unit += 1;
    192                         }
    193                         mCenterPaint.setColor(interpColor(mColors, unit));
    194                         invalidate();
    195                     }
    196                     break;
    197                 case MotionEvent.ACTION_UP:
    198                     if (mTrackingCenter) {
    199                         if (inCenter) {
    200                             mListener.colorChanged(mCenterPaint.getColor());
    201                         }
    202                         mTrackingCenter = false;    // so we draw w/o halo
    203                         invalidate();
    204                     }
    205                     break;
    206             }
    207             return true;
    208         }
    209     }
    210 
    211     public ColorPickerDialog(Context context,
    212                              OnColorChangedListener listener,
    213                              int initialColor) {
    214         super(context);
    215 
    216         mListener = listener;
    217         mInitialColor = initialColor;
    218     }
    219 
    220     @Override
    221     protected void onCreate(Bundle savedInstanceState) {
    222         super.onCreate(savedInstanceState);
    223         OnColorChangedListener l = new OnColorChangedListener() {
    224             public void colorChanged(int color) {
    225                 mListener.colorChanged(color);
    226                 dismiss();
    227             }
    228         };
    229 
    230         setContentView(new ColorPickerView(getContext(), l, mInitialColor));
    231         setTitle("Pick a Color");
    232     }
    233 }
    234