14d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb/*
24d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * Copyright (C) 2012 The Android Open Source Project
34d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb *
44d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
54d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * you may not use this file except in compliance with the License.
64d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * You may obtain a copy of the License at
74d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb *
84d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
94d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb *
104d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * Unless required by applicable law or agreed to in writing, software
114d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
124d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * See the License for the specific language governing permissions and
144d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb * limitations under the License.
154d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb */
164d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
174d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbpackage com.android.camera.ui;
184d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
194d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.content.Context;
204d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.content.res.Resources;
214d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.graphics.Canvas;
224d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.graphics.Color;
234d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.graphics.Paint;
245ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolbimport android.graphics.Rect;
254d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport android.view.ScaleGestureDetector;
264d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
274d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbimport com.android.camera.R;
284d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
294d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolbpublic class ZoomRenderer extends OverlayRenderer
304d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        implements ScaleGestureDetector.OnScaleGestureListener {
314d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
324d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private static final String TAG = "CAM_Zoom";
334d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
344d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private int mMaxZoom;
355ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    private int mMinZoom;
364d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private OnZoomChangedListener mListener;
374d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
384d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private ScaleGestureDetector mDetector;
394d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private Paint mPaint;
405ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    private Paint mTextPaint;
414d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private int mCircleSize;
424d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private int mCenterX;
434d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private int mCenterY;
444d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private float mMaxCircle;
454d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    private float mMinCircle;
460f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb    private int mInnerStroke;
470f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb    private int mOuterStroke;
485ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    private int mZoomSig;
495ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    private int mZoomFraction;
505ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    private Rect mTextBounds;
514d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
524d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public interface OnZoomChangedListener {
534d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        void onZoomStart();
544d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        void onZoomEnd();
554d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        void onZoomValueChanged(int index);  // only for immediate zoom
564d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
574d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
584d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public ZoomRenderer(Context ctx) {
594d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        Resources res = ctx.getResources();
604d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mPaint = new Paint();
614d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mPaint.setAntiAlias(true);
624d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mPaint.setColor(Color.WHITE);
634d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mPaint.setStyle(Paint.Style.STROKE);
645ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint = new Paint(mPaint);
655ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint.setStyle(Paint.Style.FILL);
665ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint.setTextSize(res.getDimensionPixelSize(R.dimen.zoom_font_size));
675ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint.setTextAlign(Paint.Align.LEFT);
685ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint.setAlpha(192);
690f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        mInnerStroke = res.getDimensionPixelSize(R.dimen.focus_inner_stroke);
700f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        mOuterStroke = res.getDimensionPixelSize(R.dimen.focus_outer_stroke);
714d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mDetector = new ScaleGestureDetector(ctx, this);
724d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mMinCircle = res.getDimensionPixelSize(R.dimen.zoom_ring_min);
735ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextBounds = new Rect();
74ad639dff251233032734106afe4fe51a52be3721Michael Kolb        setVisible(false);
754d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
764d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
774d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    // set from module
785ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    public void setZoomMax(int zoomMaxIndex) {
795ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mMaxZoom = zoomMaxIndex;
805ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mMinZoom = 0;
814d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
824d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
830af8a3b2ce98424614dd2ac33ec896142851dab5Michael Kolb    public void setZoom(int index) {
840af8a3b2ce98424614dd2ac33ec896142851dab5Michael Kolb        mCircleSize = (int) (mMinCircle + index * (mMaxCircle - mMinCircle) / (mMaxZoom - mMinZoom));
850af8a3b2ce98424614dd2ac33ec896142851dab5Michael Kolb    }
860af8a3b2ce98424614dd2ac33ec896142851dab5Michael Kolb
875ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb    public void setZoomValue(int value) {
885ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        value = value / 10;
895ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mZoomSig = value / 10;
905ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mZoomFraction = value % 10;
914d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
924d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
934d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public void setOnZoomChangeListener(OnZoomChangedListener listener) {
944d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mListener = listener;
954d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
964d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
974d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    @Override
984d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public void layout(int l, int t, int r, int b) {
994d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        super.layout(l, t, r, b);
1004d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mCenterX = (r - l) / 2;
1014d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mCenterY = (b - t) / 2;
1024d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mMaxCircle = Math.min(getWidth(), getHeight());
1034d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        mMaxCircle = (mMaxCircle - mMinCircle) / 2;
1044d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1054d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1064d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public boolean isScaling() {
1074d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        return mDetector.isInProgress();
1084d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1094d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1104d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    @Override
1114d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public void onDraw(Canvas canvas) {
1120f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        mPaint.setStrokeWidth(mInnerStroke);
1130f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        canvas.drawCircle(mCenterX, mCenterY, mMinCircle, mPaint);
1140f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        canvas.drawCircle(mCenterX, mCenterY, mMaxCircle, mPaint);
1150f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        canvas.drawLine(mCenterX - mMinCircle, mCenterY,
1160f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb                mCenterX - mMaxCircle - 4, mCenterY, mPaint);
1170f1cc66c395becb393ccd99d92475329bc6bdef5Michael Kolb        mPaint.setStrokeWidth(mOuterStroke);
118ad639dff251233032734106afe4fe51a52be3721Michael Kolb        canvas.drawCircle((float) mCenterX, (float) mCenterY,
119ad639dff251233032734106afe4fe51a52be3721Michael Kolb                (float) mCircleSize, mPaint);
1205ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        String txt = mZoomSig+"."+mZoomFraction+"x";
1215ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        mTextPaint.getTextBounds(txt, 0, txt.length(), mTextBounds);
1225ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        canvas.drawText(txt, mCenterX - mTextBounds.centerX(), mCenterY - mTextBounds.centerY(),
1235ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb                mTextPaint);
1244d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1254d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1264d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    @Override
1274d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public boolean onScale(ScaleGestureDetector detector) {
1288fd37ebbf180eb58f77ce80b07f2fd26f2bfd52aMichael Kolb        final float sf = detector.getScaleFactor();
1298fd37ebbf180eb58f77ce80b07f2fd26f2bfd52aMichael Kolb        float circle = (int) (mCircleSize * sf * sf);
1305ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        circle = Math.max(mMinCircle, circle);
1315ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        circle = Math.min(mMaxCircle, circle);
1325ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb        if (mListener != null && (int) circle != mCircleSize) {
1335ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb            mCircleSize = (int) circle;
1345ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb            int zoom = mMinZoom + (int) ((mCircleSize - mMinCircle) * (mMaxZoom - mMinZoom) / (mMaxCircle - mMinCircle));
1355ed54678384a922550428bb7ba1a3f2475c70bd3Michael Kolb            mListener.onZoomValueChanged(zoom);
1364d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        }
1374d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        return true;
1384d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1394d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1404d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    @Override
1414d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public boolean onScaleBegin(ScaleGestureDetector detector) {
142ad639dff251233032734106afe4fe51a52be3721Michael Kolb        setVisible(true);
1434d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        if (mListener != null) {
1444d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb            mListener.onZoomStart();
1454d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        }
146ad639dff251233032734106afe4fe51a52be3721Michael Kolb        update();
1474d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        return true;
1484d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1494d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1504d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    @Override
1514d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    public void onScaleEnd(ScaleGestureDetector detector) {
152ad639dff251233032734106afe4fe51a52be3721Michael Kolb        setVisible(false);
1534d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        if (mListener != null) {
1544d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb            mListener.onZoomEnd();
1554d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb        }
1564d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb    }
1574d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb
1584d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb}
159