From 4944fcd16235b27f392874f0195ca465a6199ea6 Mon Sep 17 00:00:00 2001 From: avi Date: Mon, 14 Sep 2026 08:03:33 -0500 Subject: [PATCH] Desktop: app-wide zoom (Ctrl+=/-, Ctrl+0 resets) via scaled Density --- .../main/kotlin/com/shonar/desktop/Main.kt | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/desktop/app/src/main/kotlin/com/shonar/desktop/Main.kt b/desktop/app/src/main/kotlin/com/shonar/desktop/Main.kt index e4be34d..f0b7a52 100644 --- a/desktop/app/src/main/kotlin/com/shonar/desktop/Main.kt +++ b/desktop/app/src/main/kotlin/com/shonar/desktop/Main.kt @@ -4,31 +4,71 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Surface +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.isCtrlPressed +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState +/** Scales every dp/sp in the app uniformly (fonts, paddings, controls). */ +private data class ScaledDensity(val base: Density, val zoom: Float) : Density { + override val density: Float get() = base.density * zoom + override val fontScale: Float get() = base.fontScale * zoom +} + fun main() = application { val state = remember { DesktopState() } val screen by state.screen.collectAsState() + // Ctrl+= / Ctrl+- zoom the whole app; Ctrl+0 resets (after a zoom). + var zoom by remember { mutableStateOf(1f) } Window( onCloseRequest = ::exitApplication, title = "SHONAR Desktop", state = rememberWindowState(width = 1100.dp, height = 800.dp), ) { + val baseDensity = LocalDensity.current ShonarTheme { - Surface(Modifier.fillMaxSize()) { - Box(Modifier.fillMaxSize().padding(20.dp)) { - when (screen) { - DesktopState.Screen.ENGINE -> EngineScreen(state) - DesktopState.Screen.LIBRARY -> LibraryScreen(state) - DesktopState.Screen.DETAIL -> DetailScreen(state) - DesktopState.Screen.SETTINGS -> SettingsScreen(state) + Surface( + Modifier.fillMaxSize().onPreviewKeyEvent { e -> + if (e.type != KeyEventType.KeyDown || !e.isCtrlPressed) return@onPreviewKeyEvent false + when (e.key) { + Key.Equals, Key.Plus, Key.NumPadAdd -> { + zoom = (zoom * 1.1f).coerceAtMost(3f); true + } + Key.Minus, Key.NumPadSubtract -> { + zoom = (zoom / 1.1f).coerceAtLeast(0.4f); true + } + Key.Zero, Key.NumPad0 -> { + if (zoom != 1f) { zoom = 1f; true } else false + } + else -> false + } + }, + ) { + CompositionLocalProvider( + LocalDensity provides ScaledDensity(baseDensity, zoom), + ) { + Box(Modifier.fillMaxSize().padding(20.dp)) { + when (screen) { + DesktopState.Screen.ENGINE -> EngineScreen(state) + DesktopState.Screen.LIBRARY -> LibraryScreen(state) + DesktopState.Screen.DETAIL -> DetailScreen(state) + DesktopState.Screen.SETTINGS -> SettingsScreen(state) + } } } }