1/*
2 * Copyright (C) 2013 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.colorpicker;
18
19import android.content.Context;
20import android.graphics.Bitmap;
21import android.graphics.Canvas;
22import android.graphics.Color;
23import android.graphics.LinearGradient;
24import android.graphics.Paint;
25import android.graphics.RadialGradient;
26import android.graphics.Rect;
27import android.graphics.RectF;
28import android.graphics.Shader;
29import android.graphics.SweepGradient;
30import android.util.AttributeSet;
31import android.util.DisplayMetrics;
32import android.view.MotionEvent;
33import android.view.View;
34
35import com.android.gallery3d.R;
36
37import java.util.ArrayList;
38
39public class ColorSVRectView extends View implements ColorListener {
40    private float mDpToPix;
41
42    private float mCtrY = 100;
43    private Paint mPaint1;
44
45    private float mCtrX = 100;
46    private Paint mDotPaint = new Paint();
47    private float mDotRadus;
48    private float mBorder;
49
50    private float mDotX = Float.NaN;
51    private float mDotY;
52    private int mSliderColor = 0xFF33B5E5;
53    private float[] mHSVO = new float[]{0, 1, 1, 1};
54    RectF mRect = new RectF();
55
56    private int mWidth;
57    private int mHeight;
58    public final static float DOT_SIZE = 20;
59    public final static float BORDER_SIZE = 20;
60    Bitmap mBitmap;
61
62    public ColorSVRectView(Context ctx, AttributeSet attrs) {
63        super(ctx, attrs);
64
65        DisplayMetrics metrics = ctx.getResources().getDisplayMetrics();
66        mDpToPix = metrics.density;
67        mDotRadus = DOT_SIZE * mDpToPix;
68        mBorder = BORDER_SIZE * mDpToPix;
69
70        mPaint1 = new Paint();
71
72
73        mDotPaint.setStyle(Paint.Style.FILL);
74        if (isInEditMode()) {
75            mDotPaint.setColor(0x646464);
76            mSliderColor = 0x888888;
77        } else {
78            mDotPaint.setColor(ctx.getResources().getColor(R.color.slider_dot_color));
79            mSliderColor = ctx.getResources().getColor(R.color.slider_line_color);
80        }
81        mPaint1.setStyle(Paint.Style.FILL);
82        mPaint1.setAntiAlias(true);
83        mPaint1.setFilterBitmap(true);
84
85        mBitmap = Bitmap.createBitmap(64, 46, Bitmap.Config.ARGB_8888);
86        fillBitmap();
87    }
88
89    @Override
90    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
91        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
92    }
93
94    void fillBitmap() {
95        int w = mBitmap.getWidth();
96        int h = mBitmap.getHeight();
97        int[] buff = new int[w * h];
98        float[] hsv = new float[3];
99        hsv[0] = mHSVO[0];
100        for (int i = 0; i < w * h; i++) {
101            float sat = (i % w) / (float) w;
102            float val = (w - i / w) / (float) w;
103            hsv[1] = sat;
104            hsv[2] = val;
105            buff[i] = Color.HSVToColor(hsv);
106        }
107        mBitmap.setPixels(buff, 0, w, 0, 0, w, h);
108    }
109
110    private void setUpColorPanel() {
111        updateDot();
112        updateDotPaint();
113        fillBitmap();
114
115    }
116
117
118    @Override
119    protected void onDraw(Canvas canvas) {
120        super.onDraw(canvas);
121        Rect r = canvas.getClipBounds();
122        mRect.set(r);
123        mRect.top += mBorder;
124        mRect.bottom -= mBorder;
125        mRect.left += mBorder;
126        mRect.right -= mBorder;
127        canvas.drawBitmap(mBitmap, null, mRect, mPaint1);
128
129        if (!Float.isNaN(mDotX)) {
130            canvas.drawCircle(mDotX, mDotY, mDotRadus, mDotPaint);
131        }
132    }
133
134
135    public boolean onDown(MotionEvent e) {
136        return true;
137    }
138
139    @Override
140    public boolean onTouchEvent(MotionEvent event) {
141
142        invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus),
143                (int) (mDotY + mDotRadus));
144        float x = event.getX();
145        float y = event.getY();
146
147        x = Math.max(Math.min(x, mWidth - mBorder), mBorder);
148        y = Math.max(Math.min(y, mHeight - mBorder), mBorder);
149        mDotX = x;
150        mDotY = y;
151        float sat = 1 - (mDotY - mBorder) / (mHeight - 2 * mBorder);
152        if (sat > 1) {
153            sat = 1;
154        }
155
156        float value = (mDotX - mBorder) / (mHeight - 2 * mBorder);
157        mHSVO[2] = sat;
158        mHSVO[1] = value;
159        notifyColorListeners(mHSVO);
160        updateDotPaint();
161        invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus),
162                (int) (mDotY + mDotRadus));
163
164        return true;
165    }
166
167    @Override
168    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
169        mWidth = w;
170        mHeight = h;
171        mCtrY = h / 2f;
172        mCtrX = w / 2f;
173
174        setUpColorPanel();
175    }
176
177
178    private void updateDot() {
179
180        double hue = mHSVO[0];
181        double sat = mHSVO[1];
182        double val = mHSVO[2];
183        double opc = mHSVO[3];
184
185        mDotX = (float) (mBorder + (mHeight - 2 * mBorder) * sat);
186        mDotY = (float) ((1 - val) * (mHeight - 2 * mBorder) + mBorder);
187
188    }
189
190    private void updateDotPaint() {
191        int[] colors3 = new int[]{
192                mSliderColor, mSliderColor, 0x66000000, 0};
193        RadialGradient g = new RadialGradient(mDotX, mDotY, mDotRadus, colors3, new float[]{
194                0, .3f, .31f, 1}, Shader.TileMode.CLAMP);
195        mDotPaint.setShader(g);
196
197    }
198
199    @Override
200    public void setColor(float[] hsvo) {
201        if (hsvo[0] == mHSVO[0]
202                && hsvo[1] == mHSVO[1]
203                && hsvo[2] == mHSVO[2]) {
204            mHSVO[3] = hsvo[3]; // we don't update if color stays the same
205            return;
206        }
207        System.arraycopy(hsvo, 0, mHSVO, 0, mHSVO.length);
208
209        setUpColorPanel();
210        invalidate();
211
212        updateDot();
213        updateDotPaint();
214
215    }
216
217    ArrayList<ColorListener> mColorListeners = new ArrayList<ColorListener>();
218
219    public void notifyColorListeners(float[] hsv) {
220        for (ColorListener l : mColorListeners) {
221            l.setColor(hsv);
222        }
223    }
224
225    public void addColorListener(ColorListener l) {
226        mColorListeners.add(l);
227    }
228
229    public void removeColorListener(ColorListener l) {
230        mColorListeners.remove(l);
231    }
232}
233