Skip to content

Instantly share code, notes, and snippets.

@sonique6784
Last active March 26, 2023 23:14
Show Gist options
  • Save sonique6784/513b6bc122d9e29d8a24a43fbf7e41ee to your computer and use it in GitHub Desktop.
Save sonique6784/513b6bc122d9e29d8a24a43fbf7e41ee to your computer and use it in GitHub Desktop.
/* Copyright 2023 Cedric Ferry.
SPDX-License-Identifier: Apache-2.0 */
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import kotlin.math.roundToInt
@Composable
fun DraggableToolPalette(
modifier: Modifier = Modifier,
snap: Boolean = true,
content: @Composable BoxScope.() -> Unit,
) {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
val configuration = LocalConfiguration.current
var childSize by remember { mutableStateOf(IntSize.Zero) }
Box(modifier = modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
offsetX += dragAmount.x
offsetY += dragAmount.y
val snapDistance = 10.dp.toPx()
val maxY = if (snap) {
childSize.height.toFloat()
} else {
48.dp.toPx()
}
val maxX = if (snap) {
childSize.width.toFloat()
} else {
48.dp.toPx()
}
if (offsetX < 0f || (snap && offsetX < snapDistance)) {
offsetX = 0f
}
if (offsetY < 0f || (snap && offsetY < snapDistance)) {
offsetY = 0f
}
val width = configuration.screenWidthDp.dp.toPx() - maxX
val height = configuration.screenHeightDp.dp.toPx() - maxY
if (offsetX > width || (snap && offsetX > width - snapDistance)) {
offsetX = width
}
if (offsetY > height || (snap && offsetY > height - snapDistance)) {
offsetY = height
}
}
}
) {
Box(modifier = Modifier
.onGloballyPositioned { coordinates ->
childSize = coordinates.size
}
.padding(4.dp)
.shadow(16.dp)
.border(2.dp, Color(0.9f, 0.9f, 0.9f, 1f), shape = RoundedCornerShape(8.dp))
.background(Color(0.9f, 0.9f, 0.9f, 0.9f), shape = RoundedCornerShape(8.dp))
.padding(8.dp)
.wrapContentWidth()
.wrapContentHeight()
) {
content()
}
}
}
// Usage
import androidx.compose.material.Icon
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
DraggableToolPalette() {
Column {
Text("Tools")
Row {
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Edit, "Edit")
}
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Delete, "Delete")
}
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Call, "Call")
}
}
}
}
DraggableToolPalette(snap = false) {
Column() {
Text("Tools")
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Edit, "Edit")
}
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Delete, "Delete")
}
OutlinedButton(onClick = {
}) {
Icon(Icons.Default.Call, "Call")
}
}
}
@sonique6784
Copy link
Author

Screenshot_20230327_100507

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment