1/*
2 * Copyright (C) 2012 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
17package com.android.gallery3d.filtershow.imageshow;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.graphics.Canvas;
22import android.graphics.Color;
23import android.graphics.DashPathEffect;
24import android.graphics.Matrix;
25import android.graphics.Paint;
26import android.graphics.RadialGradient;
27import android.graphics.Rect;
28import android.graphics.Shader;
29
30import com.android.gallery3d.R;
31
32public class GradControl {
33    private float mPoint1X = Float.NaN; // used to flag parameters have not been set
34    private float mPoint1Y = 0;
35    private float mPoint2X = 200;
36    private float mPoint2Y = 300;
37    private int mMinTouchDist = 80;// should be a resource & in dips
38
39    private float[] handlex = new float[3];
40    private float[] handley = new float[3];
41    private int mSliderColor;
42    private int mCenterDotSize;
43    private float mDownX;
44    private float mDownY;
45    private float mDownPoint1X;
46    private float mDownPoint1Y;
47    private float mDownPoint2X;
48    private float mDownPoint2Y;
49    Rect mImageBounds;
50    int mImageHeight;
51    private Matrix mScrToImg;
52    Paint mPaint = new Paint();
53    DashPathEffect mDash = new DashPathEffect(new float[]{30, 30}, 0);
54    private boolean mShowReshapeHandles = true;
55    public final static int HAN_CENTER = 0;
56    public final static int HAN_NORTH = 2;
57    public final static int HAN_SOUTH = 1;
58    private int[] mPointColorPatern;
59    private int[] mGrayPointColorPatern;
60    private float[] mPointRadialPos = new float[]{0, .3f, .31f, 1};
61    private int mLineColor;
62    private int mlineShadowColor;
63
64    public GradControl(Context context) {
65
66        Resources res = context.getResources();
67        mCenterDotSize = (int) res.getDimension(R.dimen.gradcontrol_dot_size);
68        mMinTouchDist = (int) res.getDimension(R.dimen.gradcontrol_min_touch_dist);
69        int grayPointCenterColor = res.getColor(R.color.gradcontrol_graypoint_center);
70        int grayPointEdgeColor = res.getColor(R.color.gradcontrol_graypoint_edge);
71        int pointCenterColor = res.getColor(R.color.gradcontrol_point_center);
72        int pointEdgeColor = res.getColor(R.color.gradcontrol_point_edge);
73        int pointShadowStartColor = res.getColor(R.color.gradcontrol_point_shadow_start);
74        int pointShadowEndColor = res.getColor(R.color.gradcontrol_point_shadow_end);
75        mPointColorPatern = new int[]{
76                pointCenterColor, pointEdgeColor, pointShadowStartColor, pointShadowEndColor};
77        mGrayPointColorPatern = new int[]{
78                grayPointCenterColor, grayPointEdgeColor, pointShadowStartColor, pointShadowEndColor};
79        mSliderColor = Color.WHITE;
80        mLineColor = res.getColor(R.color.gradcontrol_line_color);
81        mlineShadowColor = res.getColor(R.color.gradcontrol_line_shadow);
82    }
83
84    public void setPoint2(float x, float y) {
85        mPoint2X = x;
86        mPoint2Y = y;
87    }
88
89    public void setPoint1(float x, float y) {
90        mPoint1X = x;
91        mPoint1Y = y;
92    }
93
94    public int getCloseHandle(float x, float y) {
95        float min = Float.MAX_VALUE;
96        int handle = -1;
97        for (int i = 0; i < handlex.length; i++) {
98            float dx = handlex[i] - x;
99            float dy = handley[i] - y;
100            float dist = dx * dx + dy * dy;
101            if (dist < min) {
102                min = dist;
103                handle = i;
104            }
105        }
106
107        if (min < mMinTouchDist * mMinTouchDist) {
108            return handle;
109        }
110        for (int i = 0; i < handlex.length; i++) {
111            float dx = handlex[i] - x;
112            float dy = handley[i] - y;
113            float dist = (float) Math.hypot(dx, dy);
114        }
115
116        return -1;
117    }
118
119    public void setScrImageInfo(Matrix scrToImg, Rect imageBounds) {
120        mScrToImg = scrToImg;
121        mImageBounds = new Rect(imageBounds);
122    }
123
124    private boolean centerIsOutside(float x1, float y1, float x2, float y2) {
125        return (!mImageBounds.contains((int) ((x1 + x2) / 2), (int) ((y1 + y2) / 2)));
126    }
127
128    public void actionDown(float x, float y, Line line) {
129        float[] point = new float[]{
130                x, y};
131        mScrToImg.mapPoints(point);
132        mDownX = point[0];
133        mDownY = point[1];
134        mDownPoint1X = line.getPoint1X();
135        mDownPoint1Y = line.getPoint1Y();
136        mDownPoint2X = line.getPoint2X();
137        mDownPoint2Y = line.getPoint2Y();
138    }
139
140    public void actionMove(int handle, float x, float y, Line line) {
141        float[] point = new float[]{
142                x, y};
143        mScrToImg.mapPoints(point);
144        x = point[0];
145        y = point[1];
146
147        // Test if the matrix is swapping x and y
148        point[0] = 0;
149        point[1] = 1;
150        mScrToImg.mapVectors(point);
151        boolean swapxy = (point[0] > 0.0f);
152
153        int sign = 1;
154
155        float dx = x - mDownX;
156        float dy = y - mDownY;
157        switch (handle) {
158            case HAN_CENTER:
159                if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy,
160                        mDownPoint2X + dx, mDownPoint2Y + dy)) {
161                    break;
162                }
163                line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy);
164                line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy);
165                break;
166            case HAN_SOUTH:
167                if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy,
168                        mDownPoint2X, mDownPoint2Y)) {
169                    break;
170                }
171                line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy);
172                break;
173            case HAN_NORTH:
174                if (centerIsOutside(mDownPoint1X, mDownPoint1Y,
175                        mDownPoint2X + dx, mDownPoint2Y + dy)) {
176                    break;
177                }
178                line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy);
179                break;
180        }
181    }
182
183    public void paintGrayPoint(Canvas canvas, float x, float y) {
184        if (isUndefined()) {
185            return;
186        }
187
188        Paint paint = new Paint();
189        paint.setStyle(Paint.Style.FILL);
190        RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mGrayPointColorPatern,
191                mPointRadialPos, Shader.TileMode.CLAMP);
192        paint.setShader(g);
193        canvas.drawCircle(x, y, mCenterDotSize, paint);
194    }
195
196    public void paintPoint(Canvas canvas, float x, float y) {
197        if (isUndefined()) {
198            return;
199        }
200
201        Paint paint = new Paint();
202        paint.setStyle(Paint.Style.FILL);
203        RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mPointColorPatern,
204                mPointRadialPos, Shader.TileMode.CLAMP);
205        paint.setShader(g);
206        canvas.drawCircle(x, y, mCenterDotSize, paint);
207    }
208
209    void paintLines(Canvas canvas, float p1x, float p1y, float p2x, float p2y) {
210        if (isUndefined()) {
211            return;
212        }
213
214        mPaint.setAntiAlias(true);
215        mPaint.setStyle(Paint.Style.STROKE);
216
217        mPaint.setStrokeWidth(6);
218        mPaint.setColor(mlineShadowColor);
219        mPaint.setPathEffect(mDash);
220        paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y);
221
222        mPaint.setStrokeWidth(3);
223        mPaint.setColor(mLineColor);
224        mPaint.setPathEffect(mDash);
225        paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y);
226    }
227
228    public void paintOvallines(
229            Canvas canvas, Paint paint, float p1x, float p1y, float p2x, float p2y) {
230
231
232
233        canvas.drawLine(p1x, p1y, p2x, p2y, paint);
234
235        float cx = (p1x + p2x) / 2;
236        float cy = (p1y + p2y) / 2;
237        float dx = p1x - p2x;
238        float dy = p1y - p2y;
239        float len = (float) Math.hypot(dx, dy);
240        dx *= 2048 / len;
241        dy *= 2048 / len;
242
243        canvas.drawLine(p1x + dy, p1y - dx, p1x - dy, p1y + dx, paint);
244        canvas.drawLine(p2x + dy, p2y - dx, p2x - dy, p2y + dx, paint);
245    }
246
247    public void fillHandles(Canvas canvas, float p1x, float p1y, float p2x, float p2y) {
248        float cx = (p1x + p2x) / 2;
249        float cy = (p1y + p2y) / 2;
250        handlex[0] = cx;
251        handley[0] = cy;
252        handlex[1] = p1x;
253        handley[1] = p1y;
254        handlex[2] = p2x;
255        handley[2] = p2y;
256
257    }
258
259    public void draw(Canvas canvas) {
260        paintLines(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y);
261        fillHandles(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y);
262        paintPoint(canvas, mPoint2X, mPoint2Y);
263        paintPoint(canvas, mPoint1X, mPoint1Y);
264        paintPoint(canvas, (mPoint1X + mPoint2X) / 2, (mPoint1Y + mPoint2Y) / 2);
265    }
266
267    public boolean isUndefined() {
268        return Float.isNaN(mPoint1X);
269    }
270
271    public void setShowReshapeHandles(boolean showReshapeHandles) {
272        this.mShowReshapeHandles = showReshapeHandles;
273    }
274}
275