Skip to content

Commit a3c4d7f

Browse files
committed
Use telephoto library for zooming
1 parent 354aecd commit a3c4d7f

File tree

4 files changed

+26
-22
lines changed

4 files changed

+26
-22
lines changed

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ squareup-retrofit = "2.9.0"
9292
squareup-seismic = "1.0.3"
9393
squareup-workflow = "1.0.0"
9494

95+
telephoto = "0.16.0"
9596
timber = "5.0.1"
9697
truth = "1.4.4"
9798
turbine = "1.0.0"
@@ -203,7 +204,7 @@ google-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin
203204
hamcrest = "org.hamcrest:hamcrest-core:2.2"
204205

205206
java-diff-utils = { module = "io.github.java-diff-utils:java-diff-utils", version.ref = "java-diff-utils" }
206-
207+
telephoto = { module = "me.saket.telephoto:zoomable", version.ref = "telephoto" }
207208
jetbrains-annotations = "org.jetbrains:annotations:24.0.1"
208209

209210
junit = { module = "junit:junit", version.ref = "jUnit" }

workflow-trace-viewer/build.gradle.kts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
2+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
3+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
24

35
plugins {
46
id("kotlin-multiplatform")
@@ -8,6 +10,8 @@ plugins {
810

911
kotlin {
1012
jvm()
13+
14+
jvmToolchain(11)
1115

1216
sourceSets {
1317
jvmMain {
@@ -27,6 +31,10 @@ kotlin {
2731
implementation(libs.squareup.moshi.kotlin)
2832
implementation(libs.filekit.dialogs.compose)
2933
implementation(libs.java.diff.utils)
34+
implementation(libs.telephoto)
35+
36+
// Add explicit Skiko dependency for current platform
37+
implementation("org.jetbrains.skiko:skiko-awt-runtime-macos-arm64:0.9.4")
3038
}
3139
}
3240
jvmTest {
@@ -62,3 +70,9 @@ compose {
6270
tasks.named<Test>("jvmTest") {
6371
useJUnitPlatform()
6472
}
73+
74+
tasks.withType<KotlinCompile>().configureEach {
75+
compilerOptions {
76+
jvmTarget.set(JvmTarget.JVM_11)
77+
}
78+
}

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/FileTraceViewer.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ internal fun TraceViewerWindow(
111111
SearchBox(
112112
nodes = frameNodeLocations.keys.toList(),
113113
onSearch = { name ->
114-
sandboxState.scale = 1f
115114
val node = frameNodeLocations.keys.first { it.name == name }
116115
val newX = (sandboxState.offset.x - frameNodeLocations.getValue(node).x
117116
+ appWindowSize.width / 2)
@@ -144,7 +143,6 @@ internal fun TraceViewerWindow(
144143

145144
internal class SandboxState {
146145
var offset by mutableStateOf(Offset.Zero)
147-
var scale by mutableFloatStateOf(1f)
148146

149147
fun reset() {
150148
offset = Offset.Zero

workflow-trace-viewer/src/jvmMain/kotlin/com/squareup/workflow1/traceviewer/util/SandboxBackground.kt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import androidx.compose.foundation.layout.wrapContentSize
88
import androidx.compose.runtime.Composable
99
import androidx.compose.ui.Alignment
1010
import androidx.compose.ui.Modifier
11-
import androidx.compose.ui.geometry.Offset
1211
import androidx.compose.ui.graphics.graphicsLayer
1312
import androidx.compose.ui.input.pointer.PointerEventType
1413
import androidx.compose.ui.input.pointer.pointerInput
14+
import androidx.compose.ui.layout.FixedScale
1515
import androidx.compose.ui.unit.IntSize
1616
import 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

Comments
 (0)