1/*
2 * Copyright (C) 2007 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 android.graphics.drawable.shapes;
18
19import android.graphics.Canvas;
20import android.graphics.Paint;
21import android.graphics.Path;
22import android.graphics.RectF;
23
24/**
25 * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
26 * can be included (to make a sort of "O" shape).
27 * The rounded rectangle can be drawn to a Canvas with its own draw() method,
28 * but more graphical control is available if you instead pass
29 * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
30 */
31public class RoundRectShape extends RectShape {
32    private float[] mOuterRadii;
33    private RectF   mInset;
34    private float[] mInnerRadii;
35
36    private RectF mInnerRect;
37    private Path  mPath;    // this is what we actually draw
38
39    /**
40     * RoundRectShape constructor.
41     * Specifies an outer (round)rect and an optional inner (round)rect.
42     *
43     * @param outerRadii An array of 8 radius values, for the outer roundrect.
44     *                   The first two floats are for the
45     *                   top-left corner (remaining pairs correspond clockwise).
46     *                   For no rounded corners on the outer rectangle,
47     *                   pass null.
48     * @param inset      A RectF that specifies the distance from the inner
49     *                   rect to each side of the outer rect.
50     *                   For no inner, pass null.
51     * @param innerRadii An array of 8 radius values, for the inner roundrect.
52     *                   The first two floats are for the
53     *                   top-left corner (remaining pairs correspond clockwise).
54     *                   For no rounded corners on the inner rectangle,
55     *                   pass null.
56     *                   If inset parameter is null, this parameter is ignored.
57     */
58    public RoundRectShape(float[] outerRadii, RectF inset,
59                          float[] innerRadii) {
60        if (outerRadii != null && outerRadii.length < 8) {
61            throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values");
62        }
63        if (innerRadii != null && innerRadii.length < 8) {
64            throw new ArrayIndexOutOfBoundsException("inner radii must have >= 8 values");
65        }
66        mOuterRadii = outerRadii;
67        mInset = inset;
68        mInnerRadii = innerRadii;
69
70        if (inset != null) {
71            mInnerRect = new RectF();
72        }
73        mPath = new Path();
74    }
75
76    @Override
77    public void draw(Canvas canvas, Paint paint) {
78        canvas.drawPath(mPath, paint);
79    }
80
81    @Override
82    protected void onResize(float w, float h) {
83        super.onResize(w, h);
84
85        RectF r = rect();
86        mPath.reset();
87
88        if (mOuterRadii != null) {
89            mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW);
90        } else {
91            mPath.addRect(r, Path.Direction.CW);
92        }
93        if (mInnerRect != null) {
94            mInnerRect.set(r.left + mInset.left, r.top + mInset.top,
95                           r.right - mInset.right, r.bottom - mInset.bottom);
96            if (mInnerRect.width() < w && mInnerRect.height() < h) {
97                if (mInnerRadii != null) {
98                    mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW);
99                } else {
100                    mPath.addRect(mInnerRect, Path.Direction.CCW);
101                }
102            }
103        }
104    }
105
106    @Override
107    public RoundRectShape clone() throws CloneNotSupportedException {
108        RoundRectShape shape = (RoundRectShape) super.clone();
109        shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null;
110        shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null;
111        shape.mInset = new RectF(mInset);
112        shape.mInnerRect = new RectF(mInnerRect);
113        shape.mPath = new Path(mPath);
114        return shape;
115    }
116}
117