Chromium Code Reviews| Index: ui/android/java/src/org/chromium/ui/ColorPickerDialog.java |
| diff --git a/ui/android/java/src/org/chromium/ui/ColorPickerDialog.java b/ui/android/java/src/org/chromium/ui/ColorPickerDialog.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..aaca1dc1da24a702ab49fa7f40f8e16d0e3ba3bc |
| --- /dev/null |
| +++ b/ui/android/java/src/org/chromium/ui/ColorPickerDialog.java |
| @@ -0,0 +1,206 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.ui; |
| + |
| +import android.app.Dialog; |
| +import android.content.Context; |
| +import android.content.DialogInterface; |
| +import android.graphics.Canvas; |
| +import android.graphics.Color; |
| +import android.graphics.Paint; |
| +import android.graphics.RectF; |
| +import android.graphics.Shader; |
| +import android.graphics.SweepGradient; |
| +import android.os.Bundle; |
| +import android.view.MotionEvent; |
| +import android.view.View; |
| + |
| +public class ColorPickerDialog extends Dialog { |
| + |
| + public interface OnColorChangedListener { |
| + void colorChanged(int color); |
| + } |
| + |
| + private OnColorChangedListener mListener; |
| + private int mInitialColor; |
| + |
| + private static class ColorPickerView extends View { |
| + private static final int CENTER_RADIUS = 32; |
| + private static final int DIALOG_HEIGHT = 200; |
| + private static final int CONTAINER_R = 100; |
|
Peter Beverloo
2012/11/23 17:55:48
BOUNDING_BOX_EDGE maybe?
Miguel Garcia
2012/11/26 11:35:10
Done.
|
| + |
| + private Paint mPaint; |
| + private Paint mCenterPaint; |
| + private final int[] mColors; |
| + private OnColorChangedListener mListener; |
| + private boolean mTrackingCenter; |
| + private boolean mHighlightCenter; |
| + |
| + private int center_x = -1; |
| + private int center_y = -1; |
| + |
| + ColorPickerView(Context c, OnColorChangedListener listener, int color) { |
| + super(c); |
| + mListener = listener; |
|
Peter Beverloo
2012/11/23 17:55:48
Should we add a TODO about this not being the fina
Miguel Garcia
2012/11/26 11:35:10
Peter and I followed up offline and decided that t
bulach
2012/11/26 11:39:16
agree on adding a TODO / ensuring the patch descri
|
| + mColors = new int[] { |
| + 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, |
| + 0xFFFFFF00, 0xFFFF0000 |
| + }; |
| + Shader s = new SweepGradient(0, 0, mColors, null); |
| + |
| + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
| + mPaint.setShader(s); |
| + mPaint.setStyle(Paint.Style.STROKE); |
| + mPaint.setStrokeWidth(32); |
| + |
| + mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
| + mCenterPaint.setColor(color); |
| + mCenterPaint.setStrokeWidth(5); |
| + } |
| + |
| + @Override |
| + protected void onDraw(Canvas canvas) { |
| + if (center_x == -1) |
| + center_x = getWidth() / 2; |
| + if (center_y == -1) |
| + center_y = getHeight() / 2; |
| + |
| + float r = CONTAINER_R - mPaint.getStrokeWidth()*0.5f; |
| + |
| + canvas.translate(center_x, center_y); |
| + |
| + canvas.drawOval(new RectF(-r, -r, r, r), mPaint); |
| + canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint); |
| + |
| + if (mTrackingCenter) { |
| + int c = mCenterPaint.getColor(); |
| + mCenterPaint.setStyle(Paint.Style.STROKE); |
| + |
| + if (mHighlightCenter) { |
| + mCenterPaint.setAlpha(0xFF); |
| + } else { |
| + mCenterPaint.setAlpha(0x80); |
| + } |
| + canvas.drawCircle(0, 0, |
| + CENTER_RADIUS + mCenterPaint.getStrokeWidth(), |
| + mCenterPaint); |
| + |
| + mCenterPaint.setStyle(Paint.Style.FILL); |
| + mCenterPaint.setColor(c); |
| + } |
| + } |
| + |
| + @Override |
| + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| + setMeasuredDimension(widthMeasureSpec, DIALOG_HEIGHT); |
| + } |
| + |
| + private int ave(int s, int d, float p) { |
|
Peter Beverloo
2012/11/23 17:55:48
This calculates the position between [s]tart and [
Miguel Garcia
2012/11/26 11:35:10
it's actually [0,1) but yeah it's a normal interpo
|
| + return s + java.lang.Math.round(p * (d - s)); |
| + } |
| + |
| + private int interpColor(int colors[], float unit) { |
| + if (unit <= 0) { |
| + return colors[0]; |
| + } |
| + if (unit >= 1) { |
| + return colors[colors.length - 1]; |
| + } |
| + |
| + float p = unit * (colors.length - 1); |
| + int i = (int)p; |
| + p -= i; |
| + |
| + // now p is just the fractional part [0...1) and i is the index |
| + int c0 = colors[i]; |
| + int c1 = colors[i+1]; |
| + int a = ave(Color.alpha(c0), Color.alpha(c1), p); |
| + int r = ave(Color.red(c0), Color.red(c1), p); |
| + int g = ave(Color.green(c0), Color.green(c1), p); |
| + int b = ave(Color.blue(c0), Color.blue(c1), p); |
| + |
| + return Color.argb(a, r, g, b); |
| + } |
| + |
| + private static final float PI = 3.1415926f; |
| + |
| + @Override |
| + public boolean onTouchEvent(MotionEvent event) { |
| + float x = event.getX() - center_x; |
| + float y = event.getY() - center_y; |
| + boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS; |
| + |
| + switch (event.getAction()) { |
| + case MotionEvent.ACTION_DOWN: |
| + mTrackingCenter = inCenter; |
| + if (inCenter) { |
| + mHighlightCenter = true; |
| + invalidate(); |
| + break; |
| + } |
| + case MotionEvent.ACTION_MOVE: |
| + if (mTrackingCenter) { |
| + if (mHighlightCenter != inCenter) { |
| + mHighlightCenter = inCenter; |
| + invalidate(); |
| + } |
| + } else { |
| + float angle = (float)java.lang.Math.atan2(y, x); |
| + // need to turn angle [-PI ... PI] into unit [0....1] |
| + float unit = angle/(2*PI); |
| + if (unit < 0) { |
| + unit += 1; |
| + } |
| + mCenterPaint.setColor(interpColor(mColors, unit)); |
| + invalidate(); |
| + } |
| + break; |
| + case MotionEvent.ACTION_UP: |
| + if (mTrackingCenter) { |
| + if (inCenter) { |
| + mListener.colorChanged(mCenterPaint.getColor()); |
| + } |
| + mTrackingCenter = false; // so we draw w/o halo |
|
Peter Beverloo
2012/11/23 17:55:48
nit: please use whole sentences for comments.
Miguel Garcia
2012/11/26 11:35:10
Done.
|
| + invalidate(); |
| + } |
| + break; |
| + } |
| + return true; |
| + } |
| + } |
| + |
| + public ColorPickerDialog(Context context, |
| + OnColorChangedListener listener, |
| + int initialColor) { |
| + super(context); |
| + |
| + mListener = listener; |
| + mInitialColor = initialColor; |
| + |
| + |
| + setOnCancelListener(new DialogInterface.OnCancelListener() { |
| + @Override |
| + public void onCancel(DialogInterface arg0) { |
| + mListener.colorChanged(mInitialColor); |
| + } |
| + }); |
| + } |
| + |
| + @Override |
| + protected void onCreate(Bundle savedInstanceState) { |
| + super.onCreate(savedInstanceState); |
| + OnColorChangedListener listener = new OnColorChangedListener() { |
| + @Override |
| + public void colorChanged(int color) { |
| + mListener.colorChanged(color); |
| + } |
| + }; |
| + setContentView( |
| + new ColorPickerView(getContext(), listener, mInitialColor)); |
|
Peter Beverloo
2012/11/23 17:55:48
nit: this would fit on a single line.
Miguel Garcia
2012/11/26 11:35:10
Done.
|
| + |
| + // TODO(miguelg): Internationalization |
| + setTitle("Select Color"); |
| + } |
| +} |