1 /* 2 * Copyright (C) 2011 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.google.android.DemoKit; 18 19 import android.content.Context; 20 import android.graphics.*; 21 import android.util.AttributeSet; 22 import android.view.MotionEvent; 23 import android.view.View; 24 25 26 /* This class was masterfully pilfered, Carmen-Sandiego style, from our awesome sample app 27 * ApiDemos. To see how it looks as a dialog, check out: 28 * http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.html 29 * 30 */ 31 32 public class ColorWheel extends View { 33 public interface OnColorChangedListener { colorChanged(int color)34 void colorChanged(int color); 35 } 36 37 /* 38 */ 39 40 private OnColorChangedListener mListener; 41 42 private int mInitialColor; 43 44 private Paint mPaint; 45 private Paint mCenterPaint; 46 private final int[] mColors; 47 setOnColorChangedListener(OnColorChangedListener l)48 public void setOnColorChangedListener(OnColorChangedListener l) { 49 mListener = l; 50 } 51 52 ColorWheel(Context c, AttributeSet attributes)53 public ColorWheel(Context c, AttributeSet attributes) { 54 55 super(c, attributes); 56 57 mColors = new int[] { 58 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 59 0xFFFFFF00, 0xFFFF0000 60 }; 61 Shader s = new SweepGradient(0, 0, mColors, null); 62 63 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 64 mPaint.setShader(s); 65 mPaint.setStyle(Paint.Style.STROKE); 66 mPaint.setStrokeWidth(32); 67 68 mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 69 mCenterPaint.setColor(0); 70 mCenterPaint.setStrokeWidth(5); 71 } 72 73 74 75 private boolean mTrackingCenter; 76 private boolean mHighlightCenter; 77 78 @Override onDraw(Canvas canvas)79 protected void onDraw(Canvas canvas) { 80 super.onDraw(canvas); 81 float r = CENTER_X - mPaint.getStrokeWidth()*0.5f; 82 83 canvas.translate(CENTER_X, CENTER_X); 84 85 canvas.drawOval(new RectF(-r, -r, r, r), mPaint); 86 canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint); 87 88 if (mTrackingCenter) { 89 int c = mCenterPaint.getColor(); 90 mCenterPaint.setStyle(Paint.Style.STROKE); 91 92 if (mHighlightCenter) { 93 mCenterPaint.setAlpha(0xFF); 94 } else { 95 mCenterPaint.setAlpha(0x80); 96 } 97 canvas.drawCircle(0, 0, 98 CENTER_RADIUS + mCenterPaint.getStrokeWidth(), 99 mCenterPaint); 100 101 mCenterPaint.setStyle(Paint.Style.FILL); 102 mCenterPaint.setColor(c); 103 } 104 } 105 106 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)107 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 108 109 setMeasuredDimension(CENTER_X*2, CENTER_Y*2); 110 } 111 112 private static final int CENTER_X = 200; 113 private static final int CENTER_Y = 200; 114 private static final int CENTER_RADIUS = 64; 115 floatToByte(float x)116 private int floatToByte(float x) { 117 int n = java.lang.Math.round(x); 118 return n; 119 } pinToByte(int n)120 private int pinToByte(int n) { 121 if (n < 0) { 122 n = 0; 123 } else if (n > 255) { 124 n = 255; 125 } 126 return n; 127 } 128 ave(int s, int d, float p)129 private int ave(int s, int d, float p) { 130 return s + java.lang.Math.round(p * (d - s)); 131 } 132 interpColor(int colors[], float unit)133 private int interpColor(int colors[], float unit) { 134 if (unit <= 0) { 135 return colors[0]; 136 } 137 if (unit >= 1) { 138 return colors[colors.length - 1]; 139 } 140 141 float p = unit * (colors.length - 1); 142 int i = (int)p; 143 p -= i; 144 145 // now p is just the fractional part [0...1) and i is the index 146 int c0 = colors[i]; 147 int c1 = colors[i+1]; 148 int a = ave(Color.alpha(c0), Color.alpha(c1), p); 149 int r = ave(Color.red(c0), Color.red(c1), p); 150 int g = ave(Color.green(c0), Color.green(c1), p); 151 int b = ave(Color.blue(c0), Color.blue(c1), p); 152 153 return Color.argb(a, r, g, b); 154 } 155 rotateColor(int color, float rad)156 private int rotateColor(int color, float rad) { 157 float deg = rad * 180 / 3.1415927f; 158 int r = Color.red(color); 159 int g = Color.green(color); 160 int b = Color.blue(color); 161 162 ColorMatrix cm = new ColorMatrix(); 163 ColorMatrix tmp = new ColorMatrix(); 164 165 cm.setRGB2YUV(); 166 tmp.setRotate(0, deg); 167 cm.postConcat(tmp); 168 tmp.setYUV2RGB(); 169 cm.postConcat(tmp); 170 171 final float[] a = cm.getArray(); 172 173 int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b); 174 int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b); 175 int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b); 176 177 return Color.argb(Color.alpha(color), pinToByte(ir), 178 pinToByte(ig), pinToByte(ib)); 179 } 180 181 private static final float PI = 3.1415926f; 182 183 @Override onTouchEvent(MotionEvent event)184 public boolean onTouchEvent(MotionEvent event) { 185 float x = event.getX() - CENTER_X; 186 float y = event.getY() - CENTER_Y; 187 boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS; 188 189 switch (event.getAction()) { 190 case MotionEvent.ACTION_DOWN: 191 mTrackingCenter = inCenter; 192 if (inCenter) { 193 mHighlightCenter = true; 194 invalidate(); 195 break; 196 } 197 case MotionEvent.ACTION_MOVE: 198 if (mTrackingCenter) { 199 if (mHighlightCenter != inCenter) { 200 mHighlightCenter = inCenter; 201 invalidate(); 202 } 203 } else { 204 float angle = (float)java.lang.Math.atan2(y, x); 205 // need to turn angle [-PI ... PI] into unit [0....1] 206 float unit = angle/(2*PI); 207 if (unit < 0) { 208 unit += 1; 209 } 210 mCenterPaint.setColor(interpColor(mColors, unit)); 211 invalidate(); 212 mListener.colorChanged(mCenterPaint.getColor()); 213 } 214 break; 215 case MotionEvent.ACTION_UP: 216 if (mTrackingCenter) { 217 if (inCenter) { 218 mListener.colorChanged(mCenterPaint.getColor()); 219 } 220 mListener.colorChanged(0); 221 // mListener.colorChanged(mCenterPaint.getColor()); 222 mTrackingCenter = false; // so we draw w/o halo 223 invalidate(); 224 } 225 break; 226 } 227 return true; 228 } 229 } 230