Home | History | Annotate | Download | only in actions
      1 /*
      2  * Copyright (C) 2010 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.android.gallery3d.photoeditor.actions;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.Canvas;
     22 import android.graphics.Matrix;
     23 import android.graphics.Paint;
     24 import android.graphics.Path;
     25 import android.graphics.PointF;
     26 import android.graphics.RectF;
     27 import android.util.AttributeSet;
     28 import android.view.MotionEvent;
     29 
     30 /**
     31  * A view that tracks touch motions as paths and paints them as doodles.
     32  */
     33 class DoodleView extends FullscreenToolView {
     34 
     35     /**
     36      * Listener of doodle paths.
     37      */
     38     public interface OnDoodleChangeListener {
     39 
     40         void onDoodleChanged(Doodle doodle);
     41 
     42         void onDoodleFinished(Doodle doodle);
     43     }
     44 
     45     private final Paint bitmapPaint = new Paint(Paint.DITHER_FLAG);
     46     private final Paint doodlePaint = Doodle.createPaint();
     47     private final PointF lastPoint = new PointF();
     48     private final Path drawingPath = new Path();
     49     private final Matrix drawingMatrix = new Matrix();
     50     private final Matrix displayMatrix = new Matrix();
     51 
     52     private Bitmap bitmap;
     53     private Canvas bitmapCanvas;
     54     private Doodle doodle;
     55     private int color;
     56     private OnDoodleChangeListener listener;
     57 
     58     public DoodleView(Context context, AttributeSet attrs) {
     59         super(context, attrs);
     60     }
     61 
     62     public void setOnDoodleChangeListener(OnDoodleChangeListener listener) {
     63         this.listener = listener;
     64     }
     65 
     66     @Override
     67     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     68         super.onSizeChanged(w, h, oldw, oldh);
     69 
     70         RectF r = new RectF(0, 0, getPhotoWidth(), getPhotoHeight());
     71         if ((bitmap == null) && !r.isEmpty()) {
     72             bitmap = Bitmap.createBitmap((int) r.width(), (int) r.height(),
     73                     Bitmap.Config.ARGB_8888);
     74             bitmapCanvas = new Canvas(bitmap);
     75 
     76             // Set up a matrix that maps back normalized paths to be drawn on the bitmap or canvas.
     77             drawingMatrix.setRectToRect(new RectF(0, 0, 1, 1), r, Matrix.ScaleToFit.FILL);
     78         }
     79         displayMatrix.setRectToRect(r, displayBounds, Matrix.ScaleToFit.FILL);
     80     }
     81 
     82     private void drawDoodle(Canvas canvas) {
     83         if ((canvas != null) && (doodle != null)) {
     84             doodlePaint.setColor(doodle.getColor());
     85             doodle.getDrawingPath(drawingMatrix, drawingPath);
     86             canvas.drawPath(drawingPath, doodlePaint);
     87         }
     88     }
     89 
     90     public void setColor(int color) {
     91         // Restart doodle to draw in a new color.
     92         this.color = color;
     93         finishDoodle();
     94         startDoodle();
     95     }
     96 
     97     private void startDoodle() {
     98         doodle = new Doodle(color, new PointF(lastPoint.x, lastPoint.y));
     99     }
    100 
    101     private void finishDoodle() {
    102         if ((doodle != null) && !doodle.isEmpty()) {
    103             // Update the finished non-empty doodle to the bitmap.
    104             drawDoodle(bitmapCanvas);
    105             if (listener != null) {
    106                 listener.onDoodleFinished(doodle);
    107             }
    108             invalidate();
    109         }
    110         doodle = null;
    111     }
    112 
    113     private void addLastPointIntoDoodle() {
    114         if (doodle != null) {
    115             doodle.addControlPoint(new PointF(lastPoint.x, lastPoint.y));
    116             if (listener != null) {
    117                 listener.onDoodleChanged(doodle);
    118             }
    119             invalidate();
    120         }
    121     }
    122 
    123     @Override
    124     public boolean onTouchEvent(MotionEvent event) {
    125         super.onTouchEvent(event);
    126 
    127         if (isEnabled()) {
    128             float x = event.getX();
    129             float y = event.getY();
    130 
    131             switch (event.getAction()) {
    132                 case MotionEvent.ACTION_DOWN:
    133                     mapPhotoPoint(x, y, lastPoint);
    134                     startDoodle();
    135                     break;
    136 
    137                 case MotionEvent.ACTION_MOVE:
    138                     mapPhotoPoint(x, y, lastPoint);
    139                     addLastPointIntoDoodle();
    140                     break;
    141 
    142                 case MotionEvent.ACTION_CANCEL:
    143                 case MotionEvent.ACTION_UP:
    144                     // Line to last position with offset to draw at least dots for single clicks.
    145                     mapPhotoPoint(x + 1, y + 1, lastPoint);
    146                     addLastPointIntoDoodle();
    147                     finishDoodle();
    148                     break;
    149             }
    150         }
    151         return true;
    152     }
    153 
    154     @Override
    155     protected void onDraw(Canvas canvas) {
    156         super.onDraw(canvas);
    157 
    158         canvas.save();
    159         canvas.clipRect(displayBounds);
    160         canvas.concat(displayMatrix);
    161         if (bitmap != null) {
    162             canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
    163         }
    164         drawDoodle(canvas);
    165         canvas.restore();
    166     }
    167 }
    168