diff options
Diffstat (limited to 'src/com/android/gallery3d/photoeditor/actions/DoodleView.java')
-rw-r--r-- | src/com/android/gallery3d/photoeditor/actions/DoodleView.java | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/photoeditor/actions/DoodleView.java b/src/com/android/gallery3d/photoeditor/actions/DoodleView.java new file mode 100644 index 000000000..cc5af84be --- /dev/null +++ b/src/com/android/gallery3d/photoeditor/actions/DoodleView.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 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 com.android.gallery3d.photoeditor.actions; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + * A view that tracks touch motions as paths and paints them as doodles. + */ +class DoodleView extends FullscreenToolView { + + /** + * Listener of doodle paths. + */ + public interface OnDoodleChangeListener { + + void onDoodleInPhotoBounds(); + + void onDoodleFinished(Path path, int color); + } + + private final Path normalizedPath = new Path(); + private final Path drawingPath = new Path(); + private final Paint doodlePaint = new DoodlePaint(); + private final Paint bitmapPaint = new Paint(Paint.DITHER_FLAG); + private final PointF lastPoint = new PointF(); + private final Matrix pathMatrix = new Matrix(); + private final Matrix displayMatrix = new Matrix(); + + private Bitmap bitmap; + private Canvas bitmapCanvas; + private OnDoodleChangeListener listener; + + public DoodleView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setOnDoodleChangeListener(OnDoodleChangeListener listener) { + this.listener = listener; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + RectF r = new RectF(0, 0, getPhotoWidth(), getPhotoHeight()); + if ((bitmap == null) && !r.isEmpty()) { + bitmap = Bitmap.createBitmap((int) r.width(), (int) r.height(), + Bitmap.Config.ARGB_8888); + bitmap.eraseColor(0x00000000); + bitmapCanvas = new Canvas(bitmap); + + // Set up a matrix that maps back normalized paths to be drawn on the bitmap or canvas. + pathMatrix.setRectToRect(new RectF(0, 0, 1, 1), r, Matrix.ScaleToFit.FILL); + } + displayMatrix.setRectToRect(r, displayBounds, Matrix.ScaleToFit.FILL); + } + + private void drawDoodle(Canvas canvas) { + if ((canvas != null) && !normalizedPath.isEmpty()) { + drawingPath.set(normalizedPath); + drawingPath.transform(pathMatrix); + canvas.drawPath(drawingPath, doodlePaint); + } + } + + public void setColor(int color) { + // Reset path to draw in a new color. + finishCurrentPath(); + normalizedPath.moveTo(lastPoint.x, lastPoint.y); + doodlePaint.setColor(Color.argb(192, Color.red(color), Color.green(color), + Color.blue(color))); + } + + private void finishCurrentPath() { + if (!normalizedPath.isEmpty()) { + // Update the finished path to the bitmap. + drawDoodle(bitmapCanvas); + if (listener != null) { + listener.onDoodleFinished(new Path(normalizedPath), doodlePaint.getColor()); + } + normalizedPath.rewind(); + invalidate(); + } + } + + private void checkCurrentPathInBounds() { + if ((listener != null) && !normalizedPath.isEmpty()) { + RectF r = new RectF(); + normalizedPath.computeBounds(r, false); + if (r.intersects(0, 0, 1, 1)) { + listener.onDoodleInPhotoBounds(); + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + + if (isEnabled()) { + float x = event.getX(); + float y = event.getY(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mapPhotoPoint(x, y, lastPoint); + normalizedPath.moveTo(lastPoint.x, lastPoint.y); + break; + + case MotionEvent.ACTION_MOVE: + float lastX = lastPoint.x; + float lastY = lastPoint.y; + mapPhotoPoint(x, y, lastPoint); + normalizedPath.quadTo(lastX, lastY, (lastX + lastPoint.x) / 2, + (lastY + lastPoint.y) / 2); + checkCurrentPathInBounds(); + invalidate(); + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + // Line to last position with offset to draw at least dots for single clicks. + mapPhotoPoint(x + 1, y + 1, lastPoint); + normalizedPath.lineTo(lastPoint.x, lastPoint.y); + checkCurrentPathInBounds(); + finishCurrentPath(); + break; + } + } + return true; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.save(); + canvas.clipRect(displayBounds); + canvas.concat(displayMatrix); + if (bitmap != null) { + canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); + } + drawDoodle(canvas); + canvas.restore(); + } +} |