1 /*
2  * Copyright 2022 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 
17 package androidx.graphics.shapes.test
18 
19 import android.app.Activity
20 import android.graphics.Color
21 import android.graphics.Matrix
22 import android.os.Bundle
23 import android.view.View
24 import android.view.ViewGroup
25 import android.view.ViewGroup.LayoutParams
26 import android.widget.LinearLayout
27 import androidx.graphics.shapes.CornerRounding
28 import androidx.graphics.shapes.CornerRounding.Companion.Unrounded
29 import androidx.graphics.shapes.Morph
30 import androidx.graphics.shapes.RoundedPolygon
31 import androidx.graphics.shapes.circle
32 import androidx.graphics.shapes.pill
33 import androidx.graphics.shapes.pillStar
34 import androidx.graphics.shapes.rectangle
35 import androidx.graphics.shapes.star
36 import androidx.graphics.shapes.transformed
37 
38 open class ShapeActivity : Activity() {
39 
40     val shapes = mutableListOf<RoundedPolygon>()
41 
42     lateinit var morphView: MorphView
43 
44     lateinit var prevShape: RoundedPolygon
45     lateinit var currShape: RoundedPolygon
46 
onCreatenull47     override fun onCreate(savedInstanceState: Bundle?) {
48         super.onCreate(savedInstanceState)
49 
50         val container = LinearLayout(this)
51         container.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
52         container.orientation = LinearLayout.VERTICAL
53         container.setBackgroundColor(Color.BLACK)
54         setContentView(container)
55 
56         setupShapes()
57 
58         addShapeViews(container)
59 
60         setupMorphView()
61         container.addView(morphView)
62     }
63 
setupMorphViewnull64     private fun setupMorphView() {
65         val morph = Morph(prevShape, currShape)
66         if (this::morphView.isInitialized) {
67             morphView.morph = morph
68         } else {
69             morphView = MorphView(this, morph)
70         }
71     }
72 
getShapeViewnull73     private fun getShapeView(shape: RoundedPolygon, width: Int, height: Int): View {
74         val view = ShapeView(this, shape)
75         val layoutParams = LinearLayout.LayoutParams(width, height)
76         layoutParams.setMargins(5, 5, 5, 5)
77         view.layoutParams = layoutParams
78         // TODO: add click listener to show expanded version of shape at bottom of container
79         return view
80     }
81 
setupShapesnull82     internal open fun setupShapes() {
83         // Note: all RoundedPolygon(4) shapes are placeholders for shapes not yet handled
84         val matrix1 = Matrix().apply { setRotate(-45f) }
85         val matrix2 = Matrix().apply { setRotate(45f) }
86         val blobR1 = MaterialShapes.blobR(.19f, .86f).transformed(matrix1)
87         val blobR2 = MaterialShapes.blobR(.19f, .86f).transformed(matrix2)
88 
89         //        "Circle" to DefaultShapes.star(4, 1f, 1f),
90         shapes.add(RoundedPolygon.circle())
91         //        "Squirrel" to DefaultShapes.fgSquircle(0.9f),
92         shapes.add(RoundedPolygon(4))
93         //        Square, using rectangle function
94         shapes.add(RoundedPolygon.rectangle(width = 2f, height = 2f))
95         //        "Scallop" to DefaultShapes.Scallop,
96         shapes.add(MaterialShapes.scallop())
97         //        "Clover" to DefaultShapes.Clover,
98         shapes.add(MaterialShapes.clover())
99 
100         //        "Alice" to DefaultShapes.Alice,
101         shapes.add(MaterialShapes.alice())
102         //        Rectangle
103         shapes.add(RoundedPolygon.rectangle(width = 4f, height = 2f))
104         //        "Wiggle-Star" to DefaultShapes.WiggleStar,
105         shapes.add(MaterialShapes.wiggleStar())
106         //        "Wovel" to DefaultShapes.Wovel,
107         shapes.add(MaterialShapes.wovel())
108         //        "Blob Left" to DefaultShapes.BlobR.rotate(-TwoPI / 4),
109         shapes.add(blobR1)
110 
111         //        "Blob Right" to DefaultShapes.BlobR,
112         shapes.add(blobR2)
113         //        "More" to DefaultShapes.More,
114         shapes.add(MaterialShapes.more())
115         //        Round Rect
116         shapes.add(RoundedPolygon.rectangle(width = 4f, height = 2f, rounding = CornerRounding(1f)))
117         //        Round Rect (smoothed)
118         shapes.add(
119             RoundedPolygon.rectangle(width = 4f, height = 2f, rounding = CornerRounding(1f, .5f))
120         )
121         //        Round Rect (smoothed more)
122         shapes.add(
123             RoundedPolygon.rectangle(width = 4f, height = 2f, rounding = CornerRounding(1f, 1f))
124         )
125 
126         //        "CornerSW" to DefaultShapes.CornerSE.rotate(TwoPI / 4),
127         shapes.add(RoundedPolygon(4))
128         //        "CornerSE" to DefaultShapes.CornerSE,
129         shapes.add(MaterialShapes.cornerSouthEast(.4f))
130         //        "Quarty" to DefaultShapes.Quarty,
131         shapes.add(MaterialShapes.quarty(.3f, smooth = .5f))
132         //        "5D Cube" to DefaultShapes.Cube5D,
133         shapes.add(MaterialShapes.cube5D())
134         //        "Pentagon" to DefaultShapes.Pentagon
135         shapes.add(MaterialShapes.pentagon())
136 
137         // Some non-Material shapes
138 
139         val rounding = CornerRounding(.1f, .5f)
140         val starRounding = CornerRounding(.05f, .25f)
141         shapes.add(RoundedPolygon(numVertices = 4, rounding = rounding))
142         shapes.add(RoundedPolygon.star(8, radius = 1f, innerRadius = .4f, rounding = starRounding))
143         shapes.add(
144             RoundedPolygon.star(
145                 8,
146                 radius = 1f,
147                 innerRadius = .4f,
148                 rounding = starRounding,
149                 innerRounding = CornerRounding.Unrounded
150             )
151         )
152         shapes.add(
153             MaterialShapes.clover(rounding = .352f, innerRadius = .1f, innerRounding = Unrounded)
154         )
155         shapes.add(RoundedPolygon(3))
156 
157         // Pills
158         shapes.add(RoundedPolygon.pill())
159         shapes.add(RoundedPolygon.pill(15f, 1f))
160         shapes.add(RoundedPolygon.pillStar())
161         shapes.add(
162             RoundedPolygon.pillStar(numVerticesPerRadius = 10, rounding = CornerRounding(.5f))
163         )
164         shapes.add(
165             RoundedPolygon.pillStar(
166                 numVerticesPerRadius = 10,
167                 rounding = CornerRounding(.5f),
168                 innerRadiusRatio = .5f,
169                 innerRounding = CornerRounding(.2f)
170             )
171         )
172 
173         prevShape = shapes[0]
174         currShape = shapes[0]
175     }
176 
addShapeViewsnull177     private fun addShapeViews(container: ViewGroup) {
178         val WIDTH = 170
179         val HEIGHT = 170
180 
181         var shapeIndex = 0
182         var row: LinearLayout? = null
183         while (shapeIndex < shapes.size) {
184             if (shapeIndex % 6 == 0) {
185                 row = LinearLayout(this)
186                 val layoutParams =
187                     LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
188                 row.layoutParams = layoutParams
189                 row.orientation = LinearLayout.HORIZONTAL
190                 container.addView(row)
191             }
192             val shape = shapes[shapeIndex]
193             val shapeView = getShapeView(shape, WIDTH, HEIGHT)
194             row!!.addView(shapeView)
195             shapeView.setOnClickListener {
196                 prevShape = currShape
197                 currShape = shape
198                 setupMorphView()
199             }
200             ++shapeIndex
201         }
202     }
203 }
204