| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- package eu.mjdev.desktop.windows
- import androidx.compose.animation.*
- import androidx.compose.runtime.Composable
- import androidx.compose.ui.Alignment
- import androidx.compose.ui.graphics.painter.Painter
- import androidx.compose.ui.input.key.KeyEvent
- import androidx.compose.ui.unit.Dp
- import androidx.compose.ui.unit.DpSize
- import androidx.compose.ui.unit.dp
- import androidx.compose.ui.window.*
- import eu.mjdev.desktop.extensions.Compose.setWindowBounds
- import eu.mjdev.desktop.helpers.WindowFocusState.Companion.windowFocusHandler
- import eu.mjdev.desktop.provider.DesktopProvider
- import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
- import java.awt.Window
- @Composable
- fun TopWindow(
- windowState: TopWindowState,
- resizable: Boolean = false,
- title: String = "",
- icon: Painter? = null,
- focusable: Boolean = true,
- onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
- onKeyEvent: (KeyEvent) -> Boolean = { false },
- onCloseRequest: () -> Unit = {},
- onFocusChange: (hasFocus: Boolean) -> Unit = {},
- content: @Composable FrameWindowScope.() -> Unit
- ) {
- Window(
- state = windowState,
- resizable = resizable,
- undecorated = true,
- onCloseRequest = onCloseRequest,
- visible = true,
- transparent = true,
- title = title,
- icon = icon,
- focusable = focusable,
- alwaysOnTop = true,
- onPreviewKeyEvent = onPreviewKeyEvent,
- onKeyEvent = onKeyEvent,
- content = {
- windowFocusHandler { hasFocus -> onFocusChange(hasFocus) }
- windowState.window = window
- AnimatedVisibility(
- visible = windowState.isVisible,
- enter = windowState.enter,
- exit = windowState.exit,
- ) {
- content()
- }
- }
- )
- }
- data class WindowBounds(
- val x: Dp = 0.dp,
- val y: Dp = 0.dp,
- val width: Dp = 0.dp,
- val height: Dp = 0.dp
- )
- @Suppress("MemberVisibilityCanBePrivate", "unused")
- class TopWindowState(
- val containerSize: DpSize,
- override var placement: WindowPlacement,
- override var position: WindowPosition,
- override var size: DpSize = containerSize,
- override var isMinimized: Boolean = false,
- val minSize: DpSize = DpSize(0.dp, 0.dp),
- val visible: Boolean = true,
- val enter: EnterTransition = fadeIn() + expandIn(),
- val exit: ExitTransition = shrinkOut() + fadeOut(),
- val computeBounds: (visible: Boolean) -> WindowBounds = { isVisible ->
- when {
- isVisible -> WindowBounds(0.dp, 0.dp, size.width, size.height)
- else -> WindowBounds(0.dp, 0.dp, minSize.width, minSize.height)
- }
- },
- ) : WindowState {
- var isVisible: Boolean = !isMinimized && visible
- set(value) {
- field = value
- if (window != null) {
- computeBounds(value).let { bounds ->
- window?.setWindowBounds(bounds.x, bounds.y, bounds.width, bounds.height)
- }
- }
- }
- var window: Window? = null
- set(value) {
- field = value
- if (window != null) {
- computeBounds(isVisible).let { bounds ->
- value?.setWindowBounds(bounds.x, bounds.y, bounds.width, bounds.height)
- }
- }
- }
- fun hide() {
- isVisible = false
- }
- fun show() {
- isVisible = true
- }
- companion object {
- @Composable
- fun rememberTopWindowState(
- size: DpSize = DpSize(640.dp, 480.dp),
- minSize: DpSize = DpSize(0.dp, 0.dp),
- position: WindowPosition,
- visible: Boolean = true,
- placement: WindowPlacement = WindowPlacement.Floating,
- api: DesktopProvider = LocalDesktop.current,
- containerSize: DpSize = api.containerSize,
- enter: EnterTransition = fadeIn() + expandIn(),
- exit: ExitTransition = shrinkOut() + fadeOut(),
- computeBounds: (visible: Boolean) -> WindowBounds = { isVisible ->
- when {
- isVisible -> WindowBounds(0.dp, 0.dp, size.width, size.height)
- else -> WindowBounds(0.dp, 0.dp, 0.dp, 0.dp)
- }
- }
- ) = TopWindowState(
- containerSize = containerSize,
- placement = placement,
- position = position,
- size = size,
- minSize = minSize,
- computeBounds = computeBounds,
- enter = enter,
- exit = exit,
- visible = visible
- )
- @Composable
- fun rememberTopWindowState(
- size: DpSize = DpSize(640.dp, 480.dp),
- minSize: DpSize = DpSize(0.dp, 0.dp),
- position: Alignment = Alignment.BottomCenter,
- visible: Boolean = true,
- placement: WindowPlacement = WindowPlacement.Floating,
- api: DesktopProvider = LocalDesktop.current,
- containerSize: DpSize = api.containerSize,
- enter: EnterTransition = fadeIn() + expandIn(),
- exit: ExitTransition = shrinkOut() + fadeOut(),
- computeBounds: (visible: Boolean) -> WindowBounds = { isVisible ->
- when {
- isVisible -> WindowBounds(0.dp, 0.dp, size.width, size.height)
- else -> WindowBounds(0.dp, 0.dp, 0.dp, 0.dp)
- }
- }
- ) = rememberTopWindowState(
- size = size,
- minSize = minSize,
- position = WindowPosition.Aligned(position),
- placement = placement,
- api = api,
- containerSize = containerSize,
- computeBounds = computeBounds,
- enter = enter,
- exit = exit,
- visible = visible
- )
- }
- }
|