Skip to content

Commit 586fc4b

Browse files
committed
#20 Allow to sync layouts panel scale and offset with other layouts window. Works only with two opened YALI instances.
1 parent ea75633 commit 586fc4b

9 files changed

Lines changed: 84 additions & 24 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ dependencies {
6969
implementation("com.google.code.gson:gson:2.8.9")
7070
implementation("com.squareup.okhttp3:okhttp:4.9.3")
7171
implementation("com.squareup.okio:okio:3.4.0")
72-
testImplementation("junit:junit:4.12")
72+
testImplementation("junit:junit:4.13.1")
7373
}
7474

7575
tasks {

gradle.properties

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
# Gradle Releases -> https://github.com/gradle/gradle/releases
2-
gradleVersion=8.6
3-
# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3
4-
javaVersion=17
1+
# Gradle JVM settings
2+
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
53
kotlin.code.style=official
64
# Opt-out flag for bundling Kotlin standard library.
75
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
@@ -15,13 +13,13 @@ platformType=AI
1513
#TODO: set to 2025.1.1.2
1614
platformVersion=2024.3.1.7
1715
pluginGroup=com.github.grishberg.android
18-
pluginName=android-layout-inspector-plugin
16+
pluginName=YALI
1917
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
2018
# for insight into build numbers and IntelliJ Platform versions.
2119
#TODO: set to 252.*
2220
sinceBuild=243.22562.145
23-
pluginVersion=25.08.04.0
21+
pluginVersion=25.08.05.0
2422
# Use the latest of Android plugin versionAdd commentMore actions
2523
# see https://github.com/JetBrains/intellij-platform-gradle-plugin/releases
2624
androidPluginVersion=243.22562.218
27-
studioCompilePath=/Applications/Android Studio Preview.app/Contents
25+
#localASVersion=/Applications/Android Studio.app/Contents

src/main/kotlin/com/github/grishberg/android/layoutinspector/domain/LayoutResultOutput.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interface LayoutResultOutput {
66
/**
77
* Show hierarchy and screenshot
88
*/
9-
fun showResult(resultOutput: LayoutFileData, label: String? = null)
9+
fun showResult(resultOutput: LayoutFileData, isRefresh: Boolean = false)
1010

1111
fun showError(error: String)
1212

src/main/kotlin/com/github/grishberg/android/layoutinspector/domain/Logic.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import com.github.grishberg.android.layoutinspector.process.LayoutFileSystem
99
import com.github.grishberg.android.layoutinspector.process.LayoutInspectorCaptureTask
1010
import com.github.grishberg.android.layoutinspector.process.RecordingConfig
1111
import com.github.grishberg.android.layoutinspector.process.providers.ScreenSizeProvider
12+
import java.io.IOException
13+
import java.text.SimpleDateFormat
14+
import java.util.Date
1215
import kotlinx.coroutines.CoroutineExceptionHandler
1316
import kotlinx.coroutines.CoroutineScope
1417
import kotlinx.coroutines.Job
1518
import kotlinx.coroutines.async
1619
import kotlinx.coroutines.launch
17-
import java.io.IOException
18-
import java.text.SimpleDateFormat
19-
import java.util.Date
2020

2121
private const val TAG = "Logic"
2222

@@ -33,6 +33,7 @@ class Logic(
3333
private val coroutineScope: CoroutineScope,
3434
private val dispatchers: CoroutinesDispatchers
3535
) {
36+
3637
private val screenSizeProvider = ScreenSizeProvider(dispatchers)
3738
private var recordingJob: Job? = null
3839
private var isOpenedLayout = false
@@ -88,7 +89,6 @@ class Logic(
8889
val dpPerPixels = (density / 160.0)
8990
logger.d("$TAG: dp per pixels = $dpPerPixels")
9091

91-
9292
val config = RecordingConfig(
9393
recordOptions.client,
9494
window,
@@ -114,7 +114,7 @@ class Logic(
114114
}
115115
val windowList: List<ClientWindow> = windows.await()
116116
if (windowList.any { it.displayName == config.clientWindow.displayName }) {
117-
captureLayouts(config)
117+
captureLayouts(config, isRefresh = true)
118118
} else {
119119
recodLayoutFromNewDevice()
120120
}
@@ -123,7 +123,7 @@ class Logic(
123123
}
124124

125125
private suspend fun captureLayouts(
126-
config: RecordingConfig,
126+
config: RecordingConfig, isRefresh: Boolean = false
127127
) {
128128
val task = LayoutInspectorCaptureTask(layoutFileSystem, coroutineScope, logger, dispatchers)
129129

@@ -134,13 +134,12 @@ class Logic(
134134
if (liResult.data == null || liResult.root == null) {
135135
output.showError(liResult.error)
136136
} else {
137-
onSuccessCaptured(config, liResult)
137+
onSuccessCaptured(config, liResult, isRefresh)
138138
}
139139
}
140140

141141
private fun onSuccessCaptured(
142-
config: RecordingConfig,
143-
liResult: LayoutInspectorResult,
142+
config: RecordingConfig, liResult: LayoutInspectorResult, isRefresh: Boolean = false
144143
) {
145144
val dpPerPixels = config.dpPerPixels
146145
val fileNamePrefix = config.recordOptions.fileNamePrefix
@@ -158,7 +157,7 @@ class Logic(
158157
metaRepository.serialize()
159158

160159
logger.d("$TAG: Received result")
161-
output.showResult(LayoutFileData.fromLayoutInspectorResult(liResult), config.recordOptions.label)
160+
output.showResult(LayoutFileData.fromLayoutInspectorResult(liResult), isRefresh)
162161
isOpenedLayout = true
163162
}
164163

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.github.grishberg.android.layoutinspector.ui
2+
3+
import java.awt.Dimension
4+
import java.awt.geom.AffineTransform
5+
6+
data class LayoutsPreviewConfiguration(val size: Dimension, val transform: AffineTransform)

src/main/kotlin/com/github/grishberg/android/layoutinspector/ui/Main.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ class Main(
408408
copyScreenShot.addActionListener { copyScreenshotToClipboard() }
409409
toolsMenu.add(copyScreenShot)
410410

411+
val syncLayoutsScaleMenuItem = JMenuItem("Sync scale from other layouts panel")
412+
syncLayoutsScaleMenuItem.addActionListener { copyLayoutsConfiguration() }
413+
toolsMenu.add(syncLayoutsScaleMenuItem)
414+
411415
return toolsMenu
412416
}
413417

@@ -494,15 +498,15 @@ class Main(
494498
logic.openFile()
495499
}
496500

497-
override fun showResult(resultOutput: LayoutFileData, label: String?) {
501+
override fun showResult(resultOutput: LayoutFileData, label: String?, isRefresh: Boolean) {
498502
val trimmedLabel = label?.trim()
499503
if (!trimmedLabel.isNullOrEmpty()) {
500504
this.title = trimmedLabel
501505
} else {
502506
this.title = TITLE
503507
}
504508

505-
layoutPanel.showLayoutResult(resultOutput)
509+
layoutPanel.showLayoutResult(resultOutput, trimmedLabel, isRefresh)
506510
treePanel.showLayoutResult(resultOutput)
507511
findDialog.updateRootNode(resultOutput.node)
508512
splitPane1.invalidate()
@@ -671,6 +675,17 @@ class Main(
671675
layoutPanel.repaint()
672676
}
673677

678+
fun copyLayoutsConfiguration() {
679+
windowsManager.getLayoutsPreviewConfiguration(this)?.let {
680+
layoutPanel.setLayoutsConfigurationIfNeeded(it)
681+
layoutPanel.repaint()
682+
}
683+
}
684+
685+
fun getLayoutsPreviewConfiguration(): LayoutsPreviewConfiguration {
686+
return layoutPanel.getLayoutsPreviewConfiguration()
687+
}
688+
674689
private companion object {
675690
private const val TITLE = "Yet Another Android Layout Inspector."
676691
}

src/main/kotlin/com/github/grishberg/android/layoutinspector/ui/WindowsManager.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ class WindowsManager(
3030
windows.remove(window)
3131
}
3232

33+
fun getLayoutsPreviewConfiguration(currentWindow: Main): LayoutsPreviewConfiguration? {
34+
if (windows.size != 2) {
35+
logger.d("getLayoutsPreviewConfiguration: there is ${windows.size} windows")
36+
return null
37+
}
38+
39+
val referenceWindow = windows.first { it != currentWindow }
40+
return referenceWindow.getLayoutsPreviewConfiguration()
41+
}
42+
3343
fun startScreenshotTest(comparableWindow: Main): Boolean {
3444
if (windows.size != 2) {
3545
logger.d("startScreenshotTest: there is ${windows.size} windows")
@@ -62,4 +72,4 @@ class WindowsManager(
6272
)
6373
return true
6474
}
65-
}
75+
}

src/main/kotlin/com/github/grishberg/android/layoutinspector/ui/layout/LayoutPanel.kt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import com.android.layoutinspector.model.LayoutFileData
55
import com.github.grishberg.android.layoutinspector.domain.AbstractViewNode
66
import com.github.grishberg.android.layoutinspector.domain.MetaRepository
77
import com.github.grishberg.android.layoutinspector.settings.SettingsFacade
8+
import com.github.grishberg.android.layoutinspector.ui.LayoutsPreviewConfiguration
89
import com.github.grishberg.android.layoutinspector.ui.common.SimpleComponentListener
910
import com.github.grishberg.android.layoutinspector.ui.screenshottest.ScreenshotPainter
1011
import java.awt.Dimension
1112
import java.awt.Graphics
1213
import java.awt.Graphics2D
1314
import java.awt.Point
1415
import java.awt.event.ComponentEvent
16+
import java.awt.geom.AffineTransform
1517
import java.awt.geom.NoninvertibleTransformException
1618
import java.awt.geom.Point2D
1719
import java.awt.geom.Rectangle2D
@@ -97,9 +99,14 @@ class LayoutPanel(
9799
})
98100
}
99101

100-
fun showLayoutResult(layoutData: LayoutFileData) {
102+
fun showLayoutResult(layoutData: LayoutFileData, isRefresh: Boolean = false) {
101103
logic.showLayoutResult(layoutData)
102-
fitZoom()
104+
105+
// Only preserve camera position for refresh operations, reset zoom for new captures
106+
if (!isRefresh) {
107+
fitZoom()
108+
}
109+
103110
repaint()
104111
invalidate()
105112
}
@@ -183,4 +190,21 @@ class LayoutPanel(
183190
fun copyScreenshotToClipboard() {
184191
clipboardManager.copyToClipboard(screenshot)
185192
}
193+
194+
fun getLayoutsPreviewConfiguration(): LayoutsPreviewConfiguration {
195+
val transform = AffineTransform(zoomAndPanListener.getCoordTransform())
196+
this.transformedPoint
197+
return LayoutsPreviewConfiguration(
198+
size = logic.imageSize, transform = transform
199+
)
200+
}
201+
202+
fun setLayoutsConfigurationIfNeeded(cfg: LayoutsPreviewConfiguration) {
203+
if (cfg.size != logic.imageSize) {
204+
return
205+
}
206+
207+
zoomAndPanListener.setCoordinatesTransformDirect(cfg.transform)
208+
repaint()
209+
}
186210
}

src/main/kotlin/com/github/grishberg/android/layoutinspector/ui/layout/ZoomAndPanListener.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ class ZoomAndPanListener(
4444
}
4545
}
4646

47+
/**
48+
* Sets the coordinate transform directly without additional offset corrections.
49+
* Use this when copying transforms between LayoutPanels to preserve exact camera position.
50+
*/
51+
fun setCoordinatesTransformDirect(coordinatedTransform: AffineTransform) {
52+
this.coordTransform = AffineTransform(coordinatedTransform)
53+
}
54+
4755
override fun mouseClicked(e: MouseEvent) = Unit
4856
override fun mousePressed(e: MouseEvent) {
4957
val point = e.point

0 commit comments

Comments
 (0)