1+ package processing.app.ui.theme
2+
3+ import androidx.compose.foundation.layout.*
4+ import androidx.compose.runtime.Composable
5+ import androidx.compose.runtime.CompositionLocalProvider
6+ import androidx.compose.runtime.LaunchedEffect
7+ import androidx.compose.runtime.compositionLocalOf
8+ import androidx.compose.runtime.remember
9+ import androidx.compose.ui.Alignment
10+ import androidx.compose.ui.Modifier
11+ import androidx.compose.ui.awt.ComposePanel
12+ import androidx.compose.ui.unit.DpSize
13+ import androidx.compose.ui.unit.dp
14+ import androidx.compose.ui.window.Window
15+ import androidx.compose.ui.window.WindowPosition
16+ import androidx.compose.ui.window.rememberWindowState
17+ import com.formdev.flatlaf.util.SystemInfo
18+
19+ import java.awt.event.KeyAdapter
20+ import java.awt.event.KeyEvent
21+ import javax.swing.JFrame
22+
23+ val LocalWindow = compositionLocalOf<JFrame > { error(" No Window Set" ) }
24+
25+ /* *
26+ * A utility class to create a new Window with Compose content in a Swing application.
27+ * It sets up the window with some default properties and allows for custom content.
28+ * Use this when creating a Compose based window from Swing.
29+ *
30+ * Usage example:
31+ * ```
32+ * SwingUtilities.invokeLater {
33+ * PDESwingWindow("menu.help.welcome", fullWindowContent = true) {
34+ *
35+ * }
36+ * }
37+ * ```
38+ *
39+ * @param titleKey The key for the window title, which will be localized.
40+ * @param fullWindowContent If true, the content will extend into the title bar area on macOS.
41+ * @param content The composable content to be displayed in the window.
42+ */
43+ class PDESwingWindow (titleKey : String = " " , fullWindowContent : Boolean = false , onClose : () -> Unit = {}, content : @Composable BoxScope .() -> Unit ): JFrame(){
44+ init {
45+ val window = this
46+ defaultCloseOperation = DISPOSE_ON_CLOSE
47+ ComposePanel ().apply {
48+ setContent {
49+ PDEWindowContent (window, titleKey, fullWindowContent, content)
50+ }
51+ window.add(this )
52+ }
53+ background = java.awt.Color .white
54+ setLocationRelativeTo(null )
55+ addKeyListener(object : KeyAdapter () {
56+ override fun keyPressed (e : KeyEvent ) {
57+ if (e.keyCode != KeyEvent .VK_ESCAPE ) return
58+
59+ window.dispose()
60+ onClose()
61+ }
62+ })
63+ isResizable = false
64+ isVisible = true
65+ requestFocus()
66+ }
67+ }
68+
69+ /* *
70+ * Internal Composable function to set up the window content with theming and localization.
71+ * It also handles macOS specific properties for full window content.
72+ *
73+ * @param window The JFrame instance to be configured.
74+ * @param titleKey The key for the window title, which will be localized.
75+ * @param fullWindowContent If true, the content will extend into the title bar area on macOS.
76+ * @param content The composable content to be displayed in the window.
77+ */
78+ @Composable
79+ private fun PDEWindowContent (window : JFrame , titleKey : String , fullWindowContent : Boolean = false, content : @Composable BoxScope .() -> Unit ){
80+ val mac = SystemInfo .isMacOS && SystemInfo .isMacFullWindowContentSupported
81+ remember {
82+ window.rootPane.putClientProperty(" apple.awt.fullWindowContent" , mac && fullWindowContent)
83+ window.rootPane.putClientProperty(" apple.awt.transparentTitleBar" , mac && fullWindowContent)
84+ }
85+
86+ CompositionLocalProvider (LocalWindow provides window) {
87+ ProcessingTheme {
88+ val locale = LocalLocale .current
89+ window.title = locale[titleKey]
90+ LaunchedEffect (locale) {
91+ window.pack()
92+ window.setLocationRelativeTo(null )
93+ }
94+
95+ Box (modifier = Modifier .padding(top = if (mac && ! fullWindowContent) 22 .dp else 0 .dp),content = content)
96+ }
97+ }
98+ }
99+
100+ /* *
101+ * A Composable function to create and display a new window with the specified content.
102+ * This function sets up the window state and handles the close request.
103+ * Use this when creating a Compose based window from another Compose context.
104+ *
105+ * Usage example:
106+ * ```
107+ * PDEComposeWindow("window.title", fullWindowContent = true, onClose = { /* handle close */ }) {
108+ * // Your window content here
109+ * Text("Hello, World!")
110+ * }
111+ * ```
112+ *
113+ * This will create a new window with the title localized from "window.title" key,
114+ * with content extending into the title bar area on macOS, and a custom close handler.
115+ *
116+ * Fully standalone example:
117+ * ```
118+ * application {
119+ * PDEComposeWindow("window.title", fullWindowContent = true, onClose = ::exitApplication) {
120+ * // Your window content here
121+ * }
122+ * }
123+ * ```
124+ *
125+ * @param titleKey The key for the window title, which will be localized.
126+ * @param fullWindowContent If true, the content will extend into the title bar area on
127+ * macOS.
128+ * @param onClose A lambda function to be called when the window is requested to close.
129+ * @param content The composable content to be displayed in the window.
130+ *
131+ *
132+ *
133+ */
134+ @Composable
135+ fun PDEComposeWindow (titleKey : String , fullWindowContent : Boolean = false, onClose : () -> Unit = {}, content : @Composable BoxScope .() -> Unit ){
136+ val windowState = rememberWindowState(
137+ size = DpSize .Unspecified ,
138+ position = WindowPosition (Alignment .Center )
139+ )
140+ Window (onCloseRequest = onClose, state = windowState, title = " " ) {
141+ PDEWindowContent (window, titleKey, fullWindowContent, content)
142+ }
143+ }
0 commit comments