Skip to content

Commit 93b7051

Browse files
update overlay to draw shapes
Overlay can draw not only rectangle but shapes using Outline
1 parent f3b2be8 commit 93b7051

File tree

1 file changed

+61
-40
lines changed
  • cropper/src/main/java/com/smarttoolfactory/cropper

1 file changed

+61
-40
lines changed

cropper/src/main/java/com/smarttoolfactory/cropper/Overlay.kt

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import androidx.compose.ui.Modifier
77
import androidx.compose.ui.geometry.Rect
88
import androidx.compose.ui.graphics.*
99
import androidx.compose.ui.graphics.drawscope.Stroke
10+
import androidx.compose.ui.graphics.drawscope.translate
11+
import androidx.compose.ui.platform.LocalDensity
12+
import androidx.compose.ui.platform.LocalLayoutDirection
1013
import androidx.compose.ui.unit.Dp
1114
import androidx.compose.ui.unit.IntOffset
1215
import androidx.compose.ui.unit.IntSize
16+
import androidx.compose.ui.unit.LayoutDirection
1317
import com.smarttoolfactory.cropper.util.drawGrid
1418
import kotlin.math.roundToInt
1519

@@ -20,80 +24,98 @@ import kotlin.math.roundToInt
2024
@Composable
2125
internal fun DrawingOverlay(
2226
modifier: Modifier,
23-
drawOverlay:Boolean,
27+
drawOverlay: Boolean,
2428
rect: Rect,
29+
shape: Shape,
2530
drawGrid: Boolean,
2631
overlayColor: Color,
2732
handleColor: Color,
2833
strokeWidth: Dp,
2934
drawHandles: Boolean,
3035
handleSize: Float
3136
) {
37+
val density = LocalDensity.current
38+
val layoutDirection: LayoutDirection = LocalLayoutDirection.current
3239

33-
val path = remember(rect, handleSize) {
34-
Path().apply {
35-
36-
if (rect != Rect.Zero) {
37-
// Top left lines
38-
moveTo(rect.topLeft.x, rect.topLeft.y + handleSize)
39-
lineTo(rect.topLeft.x, rect.topLeft.y)
40-
lineTo(rect.topLeft.x + handleSize, rect.topLeft.y)
41-
42-
// Top right lines
43-
moveTo(rect.topRight.x - handleSize, rect.topRight.y)
44-
lineTo(rect.topRight.x, rect.topRight.y)
45-
lineTo(rect.topRight.x, rect.topRight.y + handleSize)
46-
47-
// Bottom right lines
48-
moveTo(rect.bottomRight.x, rect.bottomRight.y - handleSize)
49-
lineTo(rect.bottomRight.x, rect.bottomRight.y)
50-
lineTo(rect.bottomRight.x - handleSize, rect.bottomRight.y)
51-
52-
// Bottom left lines
53-
moveTo(rect.bottomLeft.x + handleSize, rect.bottomLeft.y)
54-
lineTo(rect.bottomLeft.x, rect.bottomLeft.y)
55-
lineTo(rect.bottomLeft.x, rect.bottomLeft.y - handleSize)
56-
}
57-
}
40+
val pathHandles = remember {
41+
Path()
42+
}
43+
44+
// TODO Update with a way that doesn't create new object on recomposition
45+
val outline = remember(rect, shape) {
46+
shape.createOutline(rect.size, layoutDirection, density)
5847
}
5948

6049
Canvas(modifier = modifier) {
6150
val strokeWidthPx = strokeWidth.toPx()
6251

52+
6353
with(drawContext.canvas.nativeCanvas) {
6454
val checkPoint = saveLayer(null, null)
6555

6656
// Destination
6757
drawRect(Color(0x77000000))
6858

6959
// Source
70-
drawRect(
71-
topLeft = rect.topLeft,
72-
size = rect.size,
73-
color = Color.Transparent,
74-
blendMode = BlendMode.Clear
75-
)
60+
translate(left = rect.left, top = rect.top) {
61+
drawOutline(
62+
outline = outline,
63+
color = Color.Transparent,
64+
blendMode = BlendMode.SrcOut
65+
)
66+
}
67+
68+
if (drawGrid) {
69+
drawGrid(
70+
rect = rect,
71+
strokeWidth = strokeWidthPx,
72+
color = overlayColor
73+
)
74+
}
75+
7676
restoreToCount(checkPoint)
7777
}
7878

79-
if(drawOverlay){
79+
if (drawOverlay) {
8080
drawRect(
8181
topLeft = rect.topLeft,
8282
size = rect.size,
8383
color = overlayColor,
8484
style = Stroke(width = strokeWidthPx)
8585
)
8686

87-
if (drawGrid) {
88-
drawGrid(rect = rect, strokeWidth = strokeWidthPx / 2, color = overlayColor)
89-
}
90-
9187
if (drawHandles) {
88+
pathHandles.apply {
89+
reset()
90+
91+
if (rect != Rect.Zero) {
92+
// Top left lines
93+
moveTo(rect.topLeft.x, rect.topLeft.y + handleSize)
94+
lineTo(rect.topLeft.x, rect.topLeft.y)
95+
lineTo(rect.topLeft.x + handleSize, rect.topLeft.y)
96+
97+
// Top right lines
98+
moveTo(rect.topRight.x - handleSize, rect.topRight.y)
99+
lineTo(rect.topRight.x, rect.topRight.y)
100+
lineTo(rect.topRight.x, rect.topRight.y + handleSize)
101+
102+
// Bottom right lines
103+
moveTo(rect.bottomRight.x, rect.bottomRight.y - handleSize)
104+
lineTo(rect.bottomRight.x, rect.bottomRight.y)
105+
lineTo(rect.bottomRight.x - handleSize, rect.bottomRight.y)
106+
107+
// Bottom left lines
108+
moveTo(rect.bottomLeft.x + handleSize, rect.bottomLeft.y)
109+
lineTo(rect.bottomLeft.x, rect.bottomLeft.y)
110+
lineTo(rect.bottomLeft.x, rect.bottomLeft.y - handleSize)
111+
}
112+
}
113+
92114
drawPath(
93-
path = path,
115+
path = pathHandles,
94116
color = handleColor,
95117
style = Stroke(
96-
width=strokeWidthPx * 2,
118+
width = strokeWidthPx * 2,
97119
cap = StrokeCap.Round,
98120
join = StrokeJoin.Round
99121
)
@@ -129,4 +151,3 @@ internal fun ImageOverlay(
129151
)
130152
}
131153
}
132-

0 commit comments

Comments
 (0)