19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics.drawable.shapes; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 207979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craikimport android.graphics.Outline; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Path; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.RectF; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can be included (to make a sort of "O" shape). 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The rounded rectangle can be drawn to a Canvas with its own draw() method, 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * but more graphical control is available if you instead pass 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}. 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class RoundRectShape extends RectShape { 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float[] mOuterRadii; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RectF mInset; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float[] mInnerRadii; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RectF mInnerRect; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Path mPath; // this is what we actually draw 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * RoundRectShape constructor. 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Specifies an outer (round)rect and an optional inner (round)rect. 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param outerRadii An array of 8 radius values, for the outer roundrect. 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The first two floats are for the 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top-left corner (remaining pairs correspond clockwise). 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For no rounded corners on the outer rectangle, 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pass null. 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inset A RectF that specifies the distance from the inner 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * rect to each side of the outer rect. 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For no inner, pass null. 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param innerRadii An array of 8 radius values, for the inner roundrect. 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The first two floats are for the 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top-left corner (remaining pairs correspond clockwise). 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For no rounded corners on the inner rectangle, 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pass null. 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If inset parameter is null, this parameter is ignored. 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RoundRectShape(float[] outerRadii, RectF inset, 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float[] innerRadii) { 619e044aed219adf52e27629d36f8ff7d670700a52Romain Guy if (outerRadii != null && outerRadii.length < 8) { 629e044aed219adf52e27629d36f8ff7d670700a52Romain Guy throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values"); 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (innerRadii != null && innerRadii.length < 8) { 659e044aed219adf52e27629d36f8ff7d670700a52Romain Guy throw new ArrayIndexOutOfBoundsException("inner radii must have >= 8 values"); 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOuterRadii = outerRadii; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInset = inset; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerRadii = innerRadii; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (inset != null) { 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerRect = new RectF(); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = new Path(); 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void draw(Canvas canvas, Paint paint) { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawPath(mPath, paint); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 817979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik 827979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik @Override 8331ba192dd201df2cad96a8c503f730130ab0d80fChris Craik public void getOutline(Outline outline) { 8431ba192dd201df2cad96a8c503f730130ab0d80fChris Craik if (mInnerRect != null) return; // have a hole, can't produce valid outline 857979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik 867979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik float radius = 0; 877979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik if (mOuterRadii != null) { 887979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik radius = mOuterRadii[0]; 897979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik for (int i = 1; i < 8; i++) { 907979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik if (mOuterRadii[i] != radius) { 917979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik // can't call simple constructors, use path 927979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik outline.setConvexPath(mPath); 9331ba192dd201df2cad96a8c503f730130ab0d80fChris Craik return; 947979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik } 957979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik } 967979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik } 977979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik 987979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik final RectF rect = rect(); 997979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top), 1007979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik (int) Math.floor(rect.right), (int) Math.floor(rect.bottom), 1017979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik radius); 1027979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik } 1037979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onResize(float w, float h) { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onResize(w, h); 1077979388d4f7d5d9dbfcf7e1cc4709f8088c034aeChris Craik 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RectF r = rect(); 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath.reset(); 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOuterRadii != null) { 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath.addRect(r, Path.Direction.CW); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerRect != null) { 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInnerRect.set(r.left + mInset.left, r.top + mInset.top, 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project r.right - mInset.right, r.bottom - mInset.bottom); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerRect.width() < w && mInnerRect.height() < h) { 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInnerRadii != null) { 1219e044aed219adf52e27629d36f8ff7d670700a52Romain Guy mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath.addRect(mInnerRect, Path.Direction.CCW); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public RoundRectShape clone() throws CloneNotSupportedException { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RoundRectShape shape = (RoundRectShape) super.clone(); 1329e044aed219adf52e27629d36f8ff7d670700a52Romain Guy shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null; 1339e044aed219adf52e27629d36f8ff7d670700a52Romain Guy shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project shape.mInset = new RectF(mInset); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project shape.mInnerRect = new RectF(mInnerRect); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project shape.mPath = new Path(mPath); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return shape; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 140