@@ -8,12 +8,14 @@ import androidx.compose.foundation.layout.wrapContentSize
88import androidx.compose.runtime.Composable
99import androidx.compose.ui.Alignment
1010import androidx.compose.ui.Modifier
11- import androidx.compose.ui.geometry.Offset
1211import androidx.compose.ui.graphics.graphicsLayer
1312import androidx.compose.ui.input.pointer.PointerEventType
1413import androidx.compose.ui.input.pointer.pointerInput
14+ import androidx.compose.ui.layout.FixedScale
1515import androidx.compose.ui.unit.IntSize
1616import com.squareup.workflow1.traceviewer.SandboxState
17+ import me.saket.telephoto.zoomable.rememberZoomableState
18+ import me.saket.telephoto.zoomable.zoomable
1719
1820/* *
1921 * This is the backdrop for the whole app. Since there can be hundreds of modules at a time, there
@@ -29,9 +31,12 @@ internal fun SandboxBackground(
2931 modifier : Modifier = Modifier ,
3032 content : @Composable () -> Unit ,
3133) {
34+ val zoomableState = rememberZoomableState()
35+
3236 Box (
3337 modifier
3438 .fillMaxSize()
39+ .zoomable(state = zoomableState)
3540 .pointerInput(Unit ) {
3641 // Panning capabilities: watches for drag gestures and applies the translation
3742 detectDragGestures { _, translation ->
@@ -45,28 +50,16 @@ internal fun SandboxBackground(
4550 val event = awaitPointerEvent()
4651 if (event.type == PointerEventType .Scroll ) {
4752 val pointerInput = event.changes.first()
48- val pointerOffsetToCenter = Offset (
49- // For some reason using 1.5 made zooming more natural than 2
50- x = pointerInput.position.x - appWindowSize.width / (3 / 2 ),
51- y = pointerInput.position.y - appWindowSize.height / 2
52- )
53- val scrollDelta = pointerInput.scrollDelta.y
5453 // Applies zoom factor based on the actual delta change rather than just the act of scrolling
5554 // This helps to normalize mouse scrolling and touchpad scrolling, since touchpad will
5655 // fire a lot more scroll events.
57- val factor = 1f + (- scrollDelta * 0.1f )
58- val minWindowSize = 0.1f
56+ val factor = 1f + (- pointerInput. scrollDelta.y * 0.1f )
57+ val minWindowSize = 0.3f
5958 val maxWindowSize = 2f
60- val oldScale = sandboxState.scale
59+ val oldScale = (zoomableState.contentScale as ? FixedScale )?.value ? : 1.0f
6160 val newScale = (oldScale * factor).coerceIn(minWindowSize, maxWindowSize)
62- val scaleRatio = newScale / oldScale
63-
64- val newOrigin = sandboxState.offset - pointerOffsetToCenter
65- val scaledView = newOrigin * scaleRatio
66- val resetViewOffset = scaledView + pointerOffsetToCenter
67- sandboxState.offset = resetViewOffset
68- sandboxState.scale = newScale
6961
62+ zoomableState.contentScale = FixedScale (newScale)
7063 event.changes.forEach { it.consume() }
7164 }
7265 }
@@ -78,8 +71,6 @@ internal fun SandboxBackground(
7871 .graphicsLayer {
7972 translationX = sandboxState.offset.x
8073 translationY = sandboxState.offset.y
81- scaleX = sandboxState.scale
82- scaleY = sandboxState.scale
8374 }
8475 ) {
8576 content()
0 commit comments