|
|
@@ -0,0 +1,92 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) Milan Jurkulák 2024.
|
|
|
+ * Contact:
|
|
|
+ * e: mimoccc@gmail.com
|
|
|
+ * e: mj@mjdev.org
|
|
|
+ * w: https://mjdev.org
|
|
|
+ */
|
|
|
+
|
|
|
+package eu.mjdev.desktop.helpers.shape
|
|
|
+
|
|
|
+import androidx.compose.ui.geometry.Rect
|
|
|
+import androidx.compose.ui.geometry.Size
|
|
|
+import androidx.compose.ui.graphics.Outline
|
|
|
+import androidx.compose.ui.graphics.Path
|
|
|
+import androidx.compose.ui.graphics.Shape
|
|
|
+import androidx.compose.ui.unit.Density
|
|
|
+import androidx.compose.ui.unit.Dp
|
|
|
+import androidx.compose.ui.unit.LayoutDirection
|
|
|
+import androidx.compose.ui.unit.dp
|
|
|
+
|
|
|
+// todo : shadow
|
|
|
+class BarShape(
|
|
|
+ private val offset: Float,
|
|
|
+ private val circleRadius: Dp,
|
|
|
+ private val cornerRadius: Dp,
|
|
|
+ private val circleGap: Dp = 5.dp,
|
|
|
+) : Shape {
|
|
|
+ override fun createOutline(
|
|
|
+ size: Size, layoutDirection: LayoutDirection, density: Density
|
|
|
+ ): Outline {
|
|
|
+ return Outline.Generic(getPath(size, density))
|
|
|
+ }
|
|
|
+
|
|
|
+ private fun getPath(size: Size, density: Density): Path {
|
|
|
+ val cutoutCenterX = offset
|
|
|
+ val cutoutRadius = density.run { (circleRadius + circleGap).toPx() }
|
|
|
+ val cornerRadiusPx = density.run { cornerRadius.toPx() }
|
|
|
+ val cornerDiameter = cornerRadiusPx * 2
|
|
|
+ return Path().apply {
|
|
|
+ val cutoutEdgeOffset = cutoutRadius * 2.5f
|
|
|
+ val cutoutLeftX = cutoutCenterX - cutoutEdgeOffset
|
|
|
+ val cutoutRightX = cutoutCenterX + cutoutEdgeOffset
|
|
|
+ moveTo(x = 0F, y = size.height)
|
|
|
+ if (cutoutLeftX > 0) {
|
|
|
+ val realLeftCornerDiameter = if (cutoutLeftX >= cornerRadiusPx) {
|
|
|
+ cornerDiameter
|
|
|
+ } else {
|
|
|
+ cutoutLeftX * 2
|
|
|
+ }
|
|
|
+ arcTo(
|
|
|
+ rect = Rect(
|
|
|
+ left = 0f, top = 0f, right = realLeftCornerDiameter, bottom = realLeftCornerDiameter
|
|
|
+ ), startAngleDegrees = 180.0f, sweepAngleDegrees = 90.0f, forceMoveTo = false
|
|
|
+ )
|
|
|
+ }
|
|
|
+ lineTo(cutoutLeftX, 0f)
|
|
|
+ cubicTo(
|
|
|
+ x1 = cutoutCenterX - cutoutRadius,
|
|
|
+ y1 = 0f,
|
|
|
+ x2 = cutoutCenterX - cutoutRadius,
|
|
|
+ y2 = cutoutRadius,
|
|
|
+ x3 = cutoutCenterX,
|
|
|
+ y3 = cutoutRadius,
|
|
|
+ )
|
|
|
+ cubicTo(
|
|
|
+ x1 = cutoutCenterX + cutoutRadius,
|
|
|
+ y1 = cutoutRadius,
|
|
|
+ x2 = cutoutCenterX + cutoutRadius,
|
|
|
+ y2 = 0f,
|
|
|
+ x3 = cutoutRightX,
|
|
|
+ y3 = 0f,
|
|
|
+ )
|
|
|
+ if (cutoutRightX < size.width) {
|
|
|
+ val realRightCornerDiameter = if (cutoutRightX <= size.width - cornerRadiusPx) {
|
|
|
+ cornerDiameter
|
|
|
+ } else {
|
|
|
+ (size.width - cutoutRightX) * 2
|
|
|
+ }
|
|
|
+ arcTo(
|
|
|
+ rect = Rect(
|
|
|
+ left = size.width - realRightCornerDiameter,
|
|
|
+ top = 0f,
|
|
|
+ right = size.width,
|
|
|
+ bottom = realRightCornerDiameter
|
|
|
+ ), startAngleDegrees = -90.0f, sweepAngleDegrees = 90.0f, forceMoveTo = false
|
|
|
+ )
|
|
|
+ }
|
|
|
+ lineTo(x = size.width, y = size.height)
|
|
|
+ close()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|