1 /*
2 * Copyright 2020 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.compose.ui.graphics.drawscope
18
19 import androidx.compose.ui.geometry.Offset
20 import androidx.compose.ui.geometry.Size
21 import androidx.compose.ui.graphics.ClipOp
22 import androidx.compose.ui.graphics.Matrix
23 import androidx.compose.ui.graphics.Path
24 import androidx.compose.ui.graphics.degrees
25 import androidx.compose.ui.graphics.internal.JvmDefaultWithCompatibility
26
27 /**
28 * Convenience method modifies the [DrawTransform] bounds to inset both left and right bounds by
29 * [horizontal] as well as the top and bottom by [vertical]. After this method is invoked, the
30 * coordinate space is returned to the state before the inset was applied
31 *
32 * @param horizontal number of pixels to inset both left and right bounds. Zero by default.
33 * @param vertical number of pixels to inset both top and bottom bounds. Zero by default.
34 */
35 @Suppress("NOTHING_TO_INLINE")
insetnull36 inline fun DrawTransform.inset(horizontal: Float = 0.0f, vertical: Float = 0.0f) =
37 inset(horizontal, vertical, horizontal, vertical)
38
39 /**
40 * Convenience method modifies the [DrawScope] bounds to inset both left, top, right and bottom
41 * bounds by [inset]. After this method is invoked, the coordinate space is returned to the state
42 * before this inset was applied.
43 *
44 * @param inset number of pixels to inset left, top, right, and bottom bounds.
45 */
46 @Suppress("NOTHING_TO_INLINE") inline fun DrawTransform.inset(inset: Float) = inset(inset, inset)
47
48 /**
49 * Add a rotation (in radians clockwise) to the current transform at the given pivot point. The
50 * pivot coordinate remains unchanged by the rotation transformation
51 *
52 * @param radians to rotate clockwise
53 * @param pivot The coordinate for the pivot point, defaults to the center of the coordinate space
54 */
55 @Suppress("NOTHING_TO_INLINE")
56 inline fun DrawTransform.rotateRad(radians: Float, pivot: Offset = center) =
57 rotate(degrees(radians), pivot)
58
59 /**
60 * Add an axis-aligned scale to the current transform, scaling uniformly in both directions by the
61 * provided scale factor at the pivot coordinate. The pivot coordinate remains unchanged by the
62 * scale transformation.
63 *
64 * @param scale The amount to scale
65 * @param pivot The coordinate for the pivot point, defaults to the center of the coordinate space
66 */
67 @Suppress("NOTHING_TO_INLINE")
68 inline fun DrawTransform.scale(scale: Float, pivot: Offset = center) = scale(scale, scale, pivot)
69
70 /** Defines transformations that can be applied to a drawing environment */
71 @DrawScopeMarker
72 @JvmDefaultWithCompatibility
73 interface DrawTransform {
74
75 /** Get the current size of the CanvasTransform */
76 val size: Size
77
78 /** Convenience method to obtain the current position of the current transformation */
79 val center: Offset
80 get() = Offset(size.width / 2, size.height / 2)
81
82 /**
83 * Simultaneously translate the coordinate space by [left] and [top] as well as modify the
84 * dimensions of the current painting area. This provides a callback to issue more drawing
85 * instructions within the modified coordinate space. This method modifies the width to be
86 * equivalent to width - (left + right) as well as height to height - (top + bottom)
87 *
88 * @param left number of pixels to inset the left drawing bound
89 * @param top number of pixels to inset the top drawing bound
90 * @param right number of pixels to inset the right drawing bound
91 * @param bottom number of pixels to inset the bottom drawing bound
92 */
93 fun inset(left: Float, top: Float, right: Float, bottom: Float)
94
95 /**
96 * Reduces the clip region to the intersection of the current clip and the given rectangle
97 * indicated by the given left, top, right and bottom bounds. After this method is invoked, this
98 * clip is no longer applied.
99 *
100 * Use [ClipOp.Difference] to subtract the provided rectangle from the current clip.
101 *
102 * @param left Left bound of the rectangle to clip
103 * @param top Top bound of the rectangle to clip
104 * @param right Right bound ofthe rectangle to clip
105 * @param bottom Bottom bound of the rectangle to clip
106 * @param clipOp Clipping operation to perform on the given bounds
107 */
108 fun clipRect(
109 left: Float = 0.0f,
110 top: Float = 0.0f,
111 right: Float = size.width,
112 bottom: Float = size.height,
113 clipOp: ClipOp = ClipOp.Intersect
114 )
115
116 /**
117 * Reduces the clip region to the intersection of the current clip and the given rounded
118 * rectangle. After this method is invoked, this clip is no longer applied
119 *
120 * @param path Shape to clip drawing content within
121 * @param clipOp Clipping operation to conduct on the given bounds, defaults to
122 * [ClipOp.Intersect]
123 */
124 fun clipPath(path: Path, clipOp: ClipOp = ClipOp.Intersect)
125
126 /**
127 * Translate the coordinate space by the given delta in pixels in both the x and y coordinates
128 * respectively
129 *
130 * @param left Pixels to translate the coordinate space in the x-axis
131 * @param top Pixels to translate the coordinate space in the y-axis
132 */
133 fun translate(left: Float = 0.0f, top: Float = 0.0f)
134
135 /**
136 * Add a rotation (in degrees clockwise) to the current transform at the given pivot point. The
137 * pivot coordinate remains unchanged by the rotation transformation.
138 *
139 * @param degrees to rotate clockwise
140 * @param pivot The coordinates for the pivot point, defaults to the center of the coordinate
141 * space
142 */
143 fun rotate(degrees: Float, pivot: Offset = center)
144
145 /**
146 * Add an axis-aligned scale to the current transform, scaling by the first argument in the
147 * horizontal direction and the second in the vertical direction at the given pivot coordinate.
148 * The pivot coordinate remains unchanged by the scale transformation.
149 *
150 * @param scaleX The amount to scale in X
151 * @param scaleY The amount to scale in Y
152 * @param pivot The coordinate for the pivot point, defaults to the center of the coordinate
153 * space
154 */
155 fun scale(scaleX: Float, scaleY: Float, pivot: Offset = center)
156
157 /**
158 * Transform the drawing environment by the given matrix
159 *
160 * @param matrix transformation matrix used to transform the drawing environment
161 */
162 fun transform(matrix: Matrix)
163 }
164