• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.photoeditor.actions;
18 
19 import android.content.Context;
20 import android.graphics.Canvas;
21 import android.graphics.Paint;
22 import android.graphics.Path;
23 import android.graphics.RectF;
24 import android.util.AttributeSet;
25 import android.view.MotionEvent;
26 import android.view.View;
27 
28 import java.util.Vector;
29 
30 /**
31  * A view that track touch motions as paths and paint them as doodles.
32  */
33 class DoodleView extends View {
34 
35     /**
36      * Listener of doodle paths.
37      */
38     public interface OnDoodleChangeListener {
39 
onLastPathChanged(Path path)40         void onLastPathChanged(Path path);
41     }
42 
43     private final Vector<ColorPath> colorPaths = new Vector<ColorPath>();
44     private final Paint paint = ColorPath.createPaint();
45 
46     private OnDoodleChangeListener listener;
47     private RectF clipBounds;
48     private float lastX;
49     private float lastY;
50 
DoodleView(Context context, AttributeSet attrs)51     public DoodleView(Context context, AttributeSet attrs) {
52         super(context, attrs);
53     }
54 
setOnDoodleChangeListener(OnDoodleChangeListener listener)55     public void setOnDoodleChangeListener(OnDoodleChangeListener listener) {
56         this.listener = listener;
57     }
58 
startPath(int color)59     public void startPath(int color) {
60         // Remove last empty path before adding a new path.
61         if (!colorPaths.isEmpty() && colorPaths.lastElement().path().isEmpty()) {
62             colorPaths.remove(colorPaths.size() - 1);
63         }
64         colorPaths.add(new ColorPath(color, new Path()));
65         colorPaths.lastElement().path().moveTo(lastX, lastY);
66     }
67 
68     /**
69      * Clears clip bounds and paths drawn.
70      */
clear()71     public void clear() {
72         colorPaths.clear();
73         clipBounds = null;
74     }
75 
76     /**
77      * Clips bounds for paths being drawn.
78      */
clipBounds(RectF bounds)79     public void clipBounds(RectF bounds) {
80         clipBounds = bounds;
81     }
82 
pathUpdated(Path path)83     private void pathUpdated(Path path) {
84         invalidate();
85         if (listener != null) {
86             listener.onLastPathChanged(path);
87         }
88     }
89 
90     @Override
onTouchEvent(MotionEvent event)91     public boolean onTouchEvent(MotionEvent event) {
92         super.onTouchEvent(event);
93 
94         if (isEnabled() && !colorPaths.isEmpty()) {
95             Path path = colorPaths.lastElement().path();
96             float x = event.getX();
97             float y = event.getY();
98 
99             switch (event.getAction()) {
100                 case MotionEvent.ACTION_DOWN:
101                     path.moveTo(x, y);
102                     pathUpdated(path);
103                     lastX = x;
104                     lastY = y;
105                     break;
106 
107                 case MotionEvent.ACTION_MOVE:
108                     path.quadTo(lastX, lastY, (lastX + x) / 2, (lastY + y) / 2);
109                     pathUpdated(path);
110                     lastX = x;
111                     lastY = y;
112                     break;
113 
114                 case MotionEvent.ACTION_CANCEL:
115                 case MotionEvent.ACTION_UP:
116                     // Line to last position with offset to draw at least dots for single clicks.
117                     path.lineTo(lastX + 1, lastY + 1);
118                     pathUpdated(path);
119                     break;
120             }
121         }
122         return true;
123     }
124 
125     @Override
onDraw(Canvas canvas)126     protected void onDraw(Canvas canvas) {
127         super.onDraw(canvas);
128 
129         canvas.save();
130         if (clipBounds != null) {
131             canvas.clipRect(clipBounds);
132         }
133         for (ColorPath colorPath : colorPaths) {
134             colorPath.draw(canvas, paint);
135         }
136         canvas.restore();
137     }
138 }
139