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.content.Context; 20 import android.graphics.*; 21 import android.os.Bundle; 22 import android.view.Menu; 23 import android.view.MenuItem; 24 import android.view.MotionEvent; 25 import android.view.View; 26 27 public class FingerPaint extends GraphicsActivity 28 implements ColorPickerDialog.OnColorChangedListener { 29 30 @Override onCreate(Bundle savedInstanceState)31 protected void onCreate(Bundle savedInstanceState) { 32 super.onCreate(savedInstanceState); 33 setContentView(new MyView(this)); 34 35 mPaint = new Paint(); 36 mPaint.setAntiAlias(true); 37 mPaint.setDither(true); 38 mPaint.setColor(0xFFFF0000); 39 mPaint.setStyle(Paint.Style.STROKE); 40 mPaint.setStrokeJoin(Paint.Join.ROUND); 41 mPaint.setStrokeCap(Paint.Cap.ROUND); 42 mPaint.setStrokeWidth(12); 43 44 mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 45 0.4f, 6, 3.5f); 46 47 mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL); 48 } 49 50 private Paint mPaint; 51 private MaskFilter mEmboss; 52 private MaskFilter mBlur; 53 colorChanged(int color)54 public void colorChanged(int color) { 55 mPaint.setColor(color); 56 } 57 58 public class MyView extends View { 59 60 private static final float MINP = 0.25f; 61 private static final float MAXP = 0.75f; 62 63 private Bitmap mBitmap; 64 private Canvas mCanvas; 65 private Path mPath; 66 private Paint mBitmapPaint; 67 MyView(Context c)68 public MyView(Context c) { 69 super(c); 70 71 mPath = new Path(); 72 mBitmapPaint = new Paint(Paint.DITHER_FLAG); 73 } 74 75 @Override onSizeChanged(int w, int h, int oldw, int oldh)76 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 77 super.onSizeChanged(w, h, oldw, oldh); 78 mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 79 mCanvas = new Canvas(mBitmap); 80 } 81 82 @Override onDraw(Canvas canvas)83 protected void onDraw(Canvas canvas) { 84 canvas.drawColor(0xFFAAAAAA); 85 86 canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); 87 88 canvas.drawPath(mPath, mPaint); 89 } 90 91 private float mX, mY; 92 private static final float TOUCH_TOLERANCE = 4; 93 touch_start(float x, float y)94 private void touch_start(float x, float y) { 95 mPath.reset(); 96 mPath.moveTo(x, y); 97 mX = x; 98 mY = y; 99 } touch_move(float x, float y)100 private void touch_move(float x, float y) { 101 float dx = Math.abs(x - mX); 102 float dy = Math.abs(y - mY); 103 if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 104 mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); 105 mX = x; 106 mY = y; 107 } 108 } touch_up()109 private void touch_up() { 110 mPath.lineTo(mX, mY); 111 // commit the path to our offscreen 112 mCanvas.drawPath(mPath, mPaint); 113 // kill this so we don't double draw 114 mPath.reset(); 115 } 116 117 @Override onTouchEvent(MotionEvent event)118 public boolean onTouchEvent(MotionEvent event) { 119 float x = event.getX(); 120 float y = event.getY(); 121 122 switch (event.getAction()) { 123 case MotionEvent.ACTION_DOWN: 124 touch_start(x, y); 125 invalidate(); 126 break; 127 case MotionEvent.ACTION_MOVE: 128 touch_move(x, y); 129 invalidate(); 130 break; 131 case MotionEvent.ACTION_UP: 132 touch_up(); 133 invalidate(); 134 break; 135 } 136 return true; 137 } 138 } 139 140 private static final int COLOR_MENU_ID = Menu.FIRST; 141 private static final int EMBOSS_MENU_ID = Menu.FIRST + 1; 142 private static final int BLUR_MENU_ID = Menu.FIRST + 2; 143 private static final int ERASE_MENU_ID = Menu.FIRST + 3; 144 private static final int SRCATOP_MENU_ID = Menu.FIRST + 4; 145 146 @Override onCreateOptionsMenu(Menu menu)147 public boolean onCreateOptionsMenu(Menu menu) { 148 super.onCreateOptionsMenu(menu); 149 150 menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c'); 151 menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's'); 152 menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z'); 153 menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z'); 154 menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z'); 155 156 /**** Is this the mechanism to extend with filter effects? 157 Intent intent = new Intent(null, getIntent().getData()); 158 intent.addCategory(Intent.CATEGORY_ALTERNATIVE); 159 menu.addIntentOptions( 160 Menu.ALTERNATIVE, 0, 161 new ComponentName(this, NotesList.class), 162 null, intent, 0, null); 163 *****/ 164 return true; 165 } 166 167 @Override onPrepareOptionsMenu(Menu menu)168 public boolean onPrepareOptionsMenu(Menu menu) { 169 super.onPrepareOptionsMenu(menu); 170 return true; 171 } 172 173 @Override onOptionsItemSelected(MenuItem item)174 public boolean onOptionsItemSelected(MenuItem item) { 175 mPaint.setXfermode(null); 176 mPaint.setAlpha(0xFF); 177 178 switch (item.getItemId()) { 179 case COLOR_MENU_ID: 180 new ColorPickerDialog(this, this, mPaint.getColor()).show(); 181 return true; 182 case EMBOSS_MENU_ID: 183 if (mPaint.getMaskFilter() != mEmboss) { 184 mPaint.setMaskFilter(mEmboss); 185 } else { 186 mPaint.setMaskFilter(null); 187 } 188 return true; 189 case BLUR_MENU_ID: 190 if (mPaint.getMaskFilter() != mBlur) { 191 mPaint.setMaskFilter(mBlur); 192 } else { 193 mPaint.setMaskFilter(null); 194 } 195 return true; 196 case ERASE_MENU_ID: 197 mPaint.setXfermode(new PorterDuffXfermode( 198 PorterDuff.Mode.CLEAR)); 199 return true; 200 case SRCATOP_MENU_ID: 201 mPaint.setXfermode(new PorterDuffXfermode( 202 PorterDuff.Mode.SRC_ATOP)); 203 mPaint.setAlpha(0x80); 204 return true; 205 } 206 return super.onOptionsItemSelected(item); 207 } 208 } 209