Mega Code Archive

 
Categories / Android / UI
 

Color Picker Dialog

/*  * Copyright (C) 2007 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package app.test; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.EmbossMaskFilter; import android.graphics.MaskFilter; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.AttributeSet; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; public class Test extends GraphicsActivity implements     ColorPickerDialog.OnColorChangedListener {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(new MyView(this));     mPaint = new Paint();     mPaint.setAntiAlias(true);     mPaint.setDither(true);     mPaint.setColor(0xFFFF0000);     mPaint.setStyle(Paint.Style.STROKE);     mPaint.setStrokeJoin(Paint.Join.ROUND);     mPaint.setStrokeCap(Paint.Cap.ROUND);     mPaint.setStrokeWidth(12);     mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);     mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);   }   private Paint mPaint;   private MaskFilter mEmboss;   private MaskFilter mBlur;   public void colorChanged(int color) {     mPaint.setColor(color);   }   public class MyView extends View {     private static final float MINP = 0.25f;     private static final float MAXP = 0.75f;     private Bitmap mBitmap;     private Canvas mCanvas;     private Path mPath;     private Paint mBitmapPaint;     public MyView(Context c) {       super(c);       mPath = new Path();       mBitmapPaint = new Paint(Paint.DITHER_FLAG);     }     @Override     protected void onSizeChanged(int w, int h, int oldw, int oldh) {       super.onSizeChanged(w, h, oldw, oldh);       mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);       mCanvas = new Canvas(mBitmap);     }     @Override     protected void onDraw(Canvas canvas) {       canvas.drawColor(0xFFAAAAAA);       canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);       canvas.drawPath(mPath, mPaint);     }     private float mX, mY;     private static final float TOUCH_TOLERANCE = 4;     private void touch_start(float x, float y) {       mPath.reset();       mPath.moveTo(x, y);       mX = x;       mY = y;     }     private void touch_move(float x, float y) {       float dx = Math.abs(x - mX);       float dy = Math.abs(y - mY);       if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {         mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);         mX = x;         mY = y;       }     }     private void touch_up() {       mPath.lineTo(mX, mY);       // commit the path to our offscreen       mCanvas.drawPath(mPath, mPaint);       // kill this so we don't double draw       mPath.reset();     }     @Override     public boolean onTouchEvent(MotionEvent event) {       float x = event.getX();       float y = event.getY();       switch (event.getAction()) {       case MotionEvent.ACTION_DOWN:         touch_start(x, y);         invalidate();         break;       case MotionEvent.ACTION_MOVE:         touch_move(x, y);         invalidate();         break;       case MotionEvent.ACTION_UP:         touch_up();         invalidate();         break;       }       return true;     }   }   private static final int COLOR_MENU_ID = Menu.FIRST;   private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;   private static final int BLUR_MENU_ID = Menu.FIRST + 2;   private static final int ERASE_MENU_ID = Menu.FIRST + 3;   private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;   @Override   public boolean onCreateOptionsMenu(Menu menu) {     super.onCreateOptionsMenu(menu);     menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');     menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');     menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');     menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');     menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');     /****      * Is this the mechanism to extend with filter effects? Intent intent =      * new Intent(null, getIntent().getData());      * intent.addCategory(Intent.CATEGORY_ALTERNATIVE);      * menu.addIntentOptions( Menu.ALTERNATIVE, 0, new ComponentName(this,      * NotesList.class), null, intent, 0, null);      *****/     return true;   }   @Override   public boolean onPrepareOptionsMenu(Menu menu) {     super.onPrepareOptionsMenu(menu);     return true;   }   @Override   public boolean onOptionsItemSelected(MenuItem item) {     mPaint.setXfermode(null);     mPaint.setAlpha(0xFF);     switch (item.getItemId()) {     case COLOR_MENU_ID:       new ColorPickerDialog(this, this, mPaint.getColor()).show();       return true;     case EMBOSS_MENU_ID:       if (mPaint.getMaskFilter() != mEmboss) {         mPaint.setMaskFilter(mEmboss);       } else {         mPaint.setMaskFilter(null);       }       return true;     case BLUR_MENU_ID:       if (mPaint.getMaskFilter() != mBlur) {         mPaint.setMaskFilter(mBlur);       } else {         mPaint.setMaskFilter(null);       }       return true;     case ERASE_MENU_ID:       mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));       return true;     case SRCATOP_MENU_ID:       mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));       mPaint.setAlpha(0x80);       return true;     }     return super.onOptionsItemSelected(item);   } } class ColorPickerDialog extends Dialog {   public interface OnColorChangedListener {     void colorChanged(int color);   }   private OnColorChangedListener mListener;   private int mInitialColor;   private static class ColorPickerView extends View {     private Paint mPaint;     private Paint mCenterPaint;     private final int[] mColors;     private OnColorChangedListener mListener;     ColorPickerView(Context c, OnColorChangedListener l, int color) {       super(c);       mListener = l;       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);     }     private boolean mTrackingCenter;     private boolean mHighlightCenter;     @Override     protected void onDraw(Canvas canvas) {       float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f;       canvas.translate(CENTER_X, CENTER_X);       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(CENTER_X * 2, CENTER_Y * 2);     }     private static final int CENTER_X = 100;     private static final int CENTER_Y = 100;     private static final int CENTER_RADIUS = 32;     private int floatToByte(float x) {       int n = java.lang.Math.round(x);       return n;     }     private int pinToByte(int n) {       if (n < 0) {         n = 0;       } else if (n > 255) {         n = 255;       }       return n;     }     private int ave(int s, int d, float p) {       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 int rotateColor(int color, float rad) {       float deg = rad * 180 / 3.1415927f;       int r = Color.red(color);       int g = Color.green(color);       int b = Color.blue(color);       ColorMatrix cm = new ColorMatrix();       ColorMatrix tmp = new ColorMatrix();       cm.setRGB2YUV();       tmp.setRotate(0, deg);       cm.postConcat(tmp);       tmp.setYUV2RGB();       cm.postConcat(tmp);       final float[] a = cm.getArray();       int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b);       int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b);       int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);       return Color.argb(Color.alpha(color), pinToByte(ir), pinToByte(ig),           pinToByte(ib));     }     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           invalidate();         }         break;       }       return true;     }   }   public ColorPickerDialog(Context context, OnColorChangedListener listener,       int initialColor) {     super(context);     mListener = listener;     mInitialColor = initialColor;   }   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     OnColorChangedListener l = new OnColorChangedListener() {       public void colorChanged(int color) {         mListener.colorChanged(color);         dismiss();       }     };     setContentView(new ColorPickerView(getContext(), l, mInitialColor));     setTitle("Pick a Color");   } } class GraphicsActivity extends Activity {   // set to true to test Picture   private static final boolean TEST_PICTURE = false;   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);   }   @Override   public void setContentView(View view) {     if (TEST_PICTURE) {       ViewGroup vg = new PictureLayout(this);       vg.addView(view);       view = vg;     }     super.setContentView(view);   } } class PictureLayout extends ViewGroup {   private final Picture mPicture = new Picture();   public PictureLayout(Context context) {     super(context);   }   public PictureLayout(Context context, AttributeSet attrs) {     super(context, attrs);   }   @Override   public void addView(View child) {     if (getChildCount() > 1) {       throw new IllegalStateException(           "PictureLayout can host only one direct child");     }     super.addView(child);   }   @Override   public void addView(View child, int index) {     if (getChildCount() > 1) {       throw new IllegalStateException(           "PictureLayout can host only one direct child");     }     super.addView(child, index);   }   @Override   public void addView(View child, LayoutParams params) {     if (getChildCount() > 1) {       throw new IllegalStateException(           "PictureLayout can host only one direct child");     }     super.addView(child, params);   }   @Override   public void addView(View child, int index, LayoutParams params) {     if (getChildCount() > 1) {       throw new IllegalStateException(           "PictureLayout can host only one direct child");     }     super.addView(child, index, params);   }   @Override   protected LayoutParams generateDefaultLayoutParams() {     return new LayoutParams(LayoutParams.MATCH_PARENT,         LayoutParams.MATCH_PARENT);   }   @Override   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     final int count = getChildCount();     int maxHeight = 0;     int maxWidth = 0;     for (int i = 0; i < count; i++) {       final View child = getChildAt(i);       if (child.getVisibility() != GONE) {         measureChild(child, widthMeasureSpec, heightMeasureSpec);       }     }     maxWidth += getPaddingLeft() + getPaddingRight();     maxHeight += getPaddingTop() + getPaddingBottom();     Drawable drawable = getBackground();     if (drawable != null) {       maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());       maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());     }     setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),         resolveSize(maxHeight, heightMeasureSpec));   }   private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx,       float sy) {     canvas.save();     canvas.translate(x, y);     canvas.clipRect(0, 0, w, h);     canvas.scale(0.5f, 0.5f);     canvas.scale(sx, sy, w, h);     canvas.drawPicture(mPicture);     canvas.restore();   }   @Override   protected void dispatchDraw(Canvas canvas) {     super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight()));     mPicture.endRecording();     int x = getWidth() / 2;     int y = getHeight() / 2;     if (false) {       canvas.drawPicture(mPicture);     } else {       drawPict(canvas, 0, 0, x, y, 1, 1);       drawPict(canvas, x, 0, x, y, -1, 1);       drawPict(canvas, 0, y, x, y, 1, -1);       drawPict(canvas, x, y, x, y, -1, -1);     }   }   @Override   public ViewParent invalidateChildInParent(int[] location, Rect dirty) {     location[0] = getLeft();     location[1] = getTop();     dirty.set(0, 0, getWidth(), getHeight());     return getParent();   }   @Override   protected void onLayout(boolean changed, int l, int t, int r, int b) {     final int count = super.getChildCount();     for (int i = 0; i < count; i++) {       final View child = getChildAt(i);       if (child.getVisibility() != GONE) {         final int childLeft = getPaddingLeft();         final int childTop = getPaddingTop();         child.layout(childLeft, childTop,             childLeft + child.getMeasuredWidth(),             childTop + child.getMeasuredHeight());       }     }   } }