From e6d6a93fd26583677089963c3f802b1d0455f5dd Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Wed, 5 Feb 2025 22:25:30 +0100
Subject: [PATCH 001/160] Show Welcome to Beta Screen
---
app/ant/processing/app/ui/WelcomeToBeta.java | 11 +++++
app/src/processing/app/UpdateCheck.java | 4 ++
app/src/processing/app/ui/WelcomeToBeta.kt | 46 ++++++++++++++++++++
3 files changed, 61 insertions(+)
create mode 100644 app/ant/processing/app/ui/WelcomeToBeta.java
create mode 100644 app/src/processing/app/ui/WelcomeToBeta.kt
diff --git a/app/ant/processing/app/ui/WelcomeToBeta.java b/app/ant/processing/app/ui/WelcomeToBeta.java
new file mode 100644
index 000000000..3127e4adc
--- /dev/null
+++ b/app/ant/processing/app/ui/WelcomeToBeta.java
@@ -0,0 +1,11 @@
+package processing.app.ui;
+
+
+// Stub class for backwards compatibility with the ant-build system
+// This class is not used in the Gradle build system
+// The actual implementation is in src/.../Schema.kt
+public class WelcomeToBeta {
+ public static void showWelcomeToBeta(){
+
+ }
+}
diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java
index 40ffe24c0..0e32a6f69 100644
--- a/app/src/processing/app/UpdateCheck.java
+++ b/app/src/processing/app/UpdateCheck.java
@@ -31,6 +31,7 @@ import java.util.Random;
import javax.swing.JOptionPane;
+import processing.app.ui.WelcomeToBeta;
import processing.core.PApplet;
@@ -134,6 +135,9 @@ public class UpdateCheck {
// offerToUpdateContributions = !promptToVisitDownloadPage();
promptToVisitDownloadPage();
}
+ if(latest < Base.getRevision()){
+ WelcomeToBeta.showWelcomeToBeta();
+ }
/*
if (offerToUpdateContributions) {
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
new file mode 100644
index 000000000..5cb3ea6f1
--- /dev/null
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -0,0 +1,46 @@
+package processing.app.ui
+
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.awt.ComposePanel
+import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.application
+import javax.swing.JFrame
+import javax.swing.SwingUtilities
+
+
+class WelcomeToBeta {
+ companion object{
+ @JvmStatic
+ fun showWelcomeToBeta() {
+ SwingUtilities.invokeLater {
+ JFrame("New Window Title").apply {
+ defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
+ contentPane.add(ComposePanel().apply {
+ setContent {
+ welcomeToBeta()
+ }
+ })
+ setSize(400, 300)
+ setLocationRelativeTo(null)
+ isVisible = true
+ }
+ }
+ }
+
+ @Composable
+ fun welcomeToBeta() {
+ Text("Welcome to the Beta version of Processing!")
+ }
+
+ @JvmStatic
+ fun main(args: Array) {
+ application {
+ Window(onCloseRequest = ::exitApplication) {
+ welcomeToBeta()
+ }
+ }
+ }
+ }
+}
+
From 4714a8b83b2b33a39c017bccce6ede37e3fe1f92 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 10:35:39 +0100
Subject: [PATCH 002/160] Welcome to Beta screen: Initial layout
---
app/build.gradle.kts | 2 +
app/src/processing/app/ui/WelcomeToBeta.kt | 80 ++++++++++++++++++++--
2 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6a0290694..05414e14d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -2,6 +2,8 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
+// TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload
+
plugins{
id("java")
kotlin("jvm") version libs.versions.kotlin
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index 5cb3ea6f1..97c4a453a 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -1,27 +1,53 @@
package processing.app.ui
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposePanel
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Window
+import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
+import androidx.compose.ui.window.rememberWindowState
+
import javax.swing.JFrame
import javax.swing.SwingUtilities
class WelcomeToBeta {
companion object{
+ val windowSize = Pair(400, 200)
+ val windowTitle = "Welcome to Beta"
+ val title = "Welcome to the Processing Beta"
+ val message = """Thank you for trying out the new version of Processing. We’re very grateful!
+
+Please report any bugs on the forums."""
+ val buttonText = "Thank you"
+
+
@JvmStatic
fun showWelcomeToBeta() {
SwingUtilities.invokeLater {
- JFrame("New Window Title").apply {
+ JFrame(windowTitle).apply {
defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
contentPane.add(ComposePanel().apply {
setContent {
welcomeToBeta()
}
})
- setSize(400, 300)
+// setSize(windowSize.first, windowSize.second)
setLocationRelativeTo(null)
isVisible = true
}
@@ -30,14 +56,58 @@ class WelcomeToBeta {
@Composable
fun welcomeToBeta() {
- Text("Welcome to the Beta version of Processing!")
+ // TODO: Add fonts and colors
+
+ Row(
+ modifier = Modifier
+ .padding(20.dp, 10.dp)
+ .size(windowSize.first.dp, windowSize.second.dp),
+ horizontalArrangement = Arrangement.spacedBy(20.dp)
+ )
+ {
+ // TODO: Add the Processing logo svg here
+ Box(modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .size(100.dp, 100.dp)
+ .background(Color.Blue)
+ )
+ Column(modifier = Modifier
+ .fillMaxHeight(),
+ verticalArrangement = Arrangement.spacedBy(20.dp, alignment = Alignment.CenterVertically)
+ ) {
+ Text(title, fontSize = 17.sp, fontWeight = FontWeight.SemiBold)
+ Text(message, fontSize = 13.sp)
+ Row {
+ Spacer(modifier = Modifier.weight(1f))
+ // TODO Add button shadow and make interactive
+ Box(
+ modifier = Modifier
+ .background(Color.Blue)
+ .padding(10.dp)
+ .sizeIn(minWidth = 100.dp)
+
+ ,
+ contentAlignment = Alignment.Center
+ ) {
+ Text(buttonText, color = Color.White)
+ }
+ }
+ }
+ }
}
@JvmStatic
fun main(args: Array) {
application {
- Window(onCloseRequest = ::exitApplication) {
- welcomeToBeta()
+ val windowState = rememberWindowState(
+ size = DpSize.Unspecified,
+ position = WindowPosition(Alignment.Center)
+ )
+ Window(onCloseRequest = ::exitApplication, state = windowState, title = windowTitle) {
+ Surface(color = Color.White) {
+ welcomeToBeta()
+ }
+
}
}
}
From 5ce873d21bbdb6e8a54ac867395c9d2466efc803 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 13:09:39 +0100
Subject: [PATCH 003/160] Welcome to Beta screen: SVG Logo
---
app/src/main/resources/logo.svg | 5 +++
app/src/processing/app/ui/WelcomeToBeta.kt | 47 ++++++++++++----------
2 files changed, 31 insertions(+), 21 deletions(-)
create mode 100644 app/src/main/resources/logo.svg
diff --git a/app/src/main/resources/logo.svg b/app/src/main/resources/logo.svg
new file mode 100644
index 000000000..aa04fcb29
--- /dev/null
+++ b/app/src/main/resources/logo.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index 97c4a453a..79635be18 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -1,18 +1,16 @@
package processing.app.ui
+import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
-import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposePanel
-import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
@@ -21,6 +19,7 @@ import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
+import java.awt.Dimension
import javax.swing.JFrame
import javax.swing.SwingUtilities
@@ -28,7 +27,7 @@ import javax.swing.SwingUtilities
class WelcomeToBeta {
companion object{
- val windowSize = Pair(400, 200)
+ val windowSize = Dimension(400, 200)
val windowTitle = "Welcome to Beta"
val title = "Welcome to the Processing Beta"
val message = """Thank you for trying out the new version of Processing. We’re very grateful!
@@ -46,8 +45,8 @@ Please report any bugs on the forums."""
setContent {
welcomeToBeta()
}
+ size = windowSize
})
-// setSize(windowSize.first, windowSize.second)
setLocationRelativeTo(null)
isVisible = true
}
@@ -61,22 +60,30 @@ Please report any bugs on the forums."""
Row(
modifier = Modifier
.padding(20.dp, 10.dp)
- .size(windowSize.first.dp, windowSize.second.dp),
+ .size(windowSize.width.dp, windowSize.height.dp),
horizontalArrangement = Arrangement.spacedBy(20.dp)
- )
- {
- // TODO: Add the Processing logo svg here
- Box(modifier = Modifier
- .align(Alignment.CenterVertically)
- .size(100.dp, 100.dp)
- .background(Color.Blue)
+ ){
+ Image(
+ painter = painterResource("logo.svg"),
+ contentDescription = "Processing Logo",
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .size(100.dp, 100.dp)
)
- Column(modifier = Modifier
- .fillMaxHeight(),
+ Column(
+ modifier = Modifier
+ .fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(20.dp, alignment = Alignment.CenterVertically)
) {
- Text(title, fontSize = 17.sp, fontWeight = FontWeight.SemiBold)
- Text(message, fontSize = 13.sp)
+ Text(
+ title,
+ fontSize = 17.sp,
+ fontWeight = FontWeight.SemiBold
+ )
+ Text(
+ message,
+ fontSize = 13.sp
+ )
Row {
Spacer(modifier = Modifier.weight(1f))
// TODO Add button shadow and make interactive
@@ -84,9 +91,7 @@ Please report any bugs on the forums."""
modifier = Modifier
.background(Color.Blue)
.padding(10.dp)
- .sizeIn(minWidth = 100.dp)
-
- ,
+ .sizeIn(minWidth = 100.dp),
contentAlignment = Alignment.Center
) {
Text(buttonText, color = Color.White)
From a3635bc74851dd5d15b219acb0763fe91d77a3e2 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 14:45:47 +0100
Subject: [PATCH 004/160] Welcome to Beta screen: Animations, Interaction
---
app/src/processing/app/ui/WelcomeToBeta.kt | 97 ++++++++++++++++++----
1 file changed, 80 insertions(+), 17 deletions(-)
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index 79635be18..773e81be1 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -1,15 +1,22 @@
package processing.app.ui
+import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Surface
import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposePanel
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.PointerEventType
+import androidx.compose.ui.input.pointer.PointerIcon
+import androidx.compose.ui.input.pointer.onPointerEvent
+import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpSize
@@ -19,8 +26,11 @@ import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
+import com.formdev.flatlaf.util.SystemInfo
+import java.awt.Cursor
import java.awt.Dimension
-
+import java.awt.event.KeyAdapter
+import java.awt.event.KeyEvent
import javax.swing.JFrame
import javax.swing.SwingUtilities
@@ -35,32 +45,47 @@ class WelcomeToBeta {
Please report any bugs on the forums."""
val buttonText = "Thank you"
-
@JvmStatic
fun showWelcomeToBeta() {
+ val mac = SystemInfo.isMacFullWindowContentSupported
SwingUtilities.invokeLater {
JFrame(windowTitle).apply {
+ val close = { dispose() }
+ rootPane.putClientProperty("apple.awt.transparentTitleBar", mac)
+ rootPane.putClientProperty("apple.awt.fullWindowContent", mac)
defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
contentPane.add(ComposePanel().apply {
- setContent {
- welcomeToBeta()
- }
size = windowSize
+ setContent {
+ Box(modifier = Modifier.padding(top = if(mac) 22.dp else 0.dp)) {
+ welcomeToBeta(close)
+ }
+ }
})
+ pack()
+ background = java.awt.Color.white
setLocationRelativeTo(null)
+ addKeyListener(object : KeyAdapter() {
+ override fun keyPressed(e: KeyEvent) {
+ if (e.keyCode == KeyEvent.VK_ESCAPE) close()
+ }
+ })
+ isResizable = false
isVisible = true
+ requestFocus()
}
}
}
@Composable
- fun welcomeToBeta() {
+ fun welcomeToBeta(close: () -> Unit = {}) {
// TODO: Add fonts and colors
Row(
modifier = Modifier
.padding(20.dp, 10.dp)
- .size(windowSize.width.dp, windowSize.height.dp),
+ .size(windowSize.width.dp, windowSize.height.dp)
+ ,
horizontalArrangement = Arrangement.spacedBy(20.dp)
){
Image(
@@ -86,20 +111,55 @@ Please report any bugs on the forums."""
)
Row {
Spacer(modifier = Modifier.weight(1f))
- // TODO Add button shadow and make interactive
- Box(
- modifier = Modifier
- .background(Color.Blue)
- .padding(10.dp)
- .sizeIn(minWidth = 100.dp),
- contentAlignment = Alignment.Center
- ) {
+ PDEButton(onClick = {
+ close()
+ }) {
Text(buttonText, color = Color.White)
}
}
}
}
}
+ @OptIn(ExperimentalComposeUiApi::class)
+ @Composable
+ fun PDEButton(onClick: () -> Unit, content: @Composable BoxScope.() -> Unit) {
+ var hover by remember { mutableStateOf(false) }
+ var clicked by remember { mutableStateOf(false) }
+ val offset by animateFloatAsState(if (hover) -5f else 5f)
+ val color by animateColorAsState(if(clicked) Color.Black else Color.Blue)
+
+ Box(modifier = Modifier.padding(end = 5.dp, top = 5.dp)) {
+ Box(
+ modifier = Modifier
+ .offset((-offset).dp, (offset).dp)
+ .background(Color.Gray)
+ .matchParentSize()
+ )
+ Box(
+ modifier = Modifier
+ .onPointerEvent(PointerEventType.Press) {
+ clicked = true
+ }
+ .onPointerEvent(PointerEventType.Release) {
+ clicked = false
+ onClick()
+ }
+ .onPointerEvent(PointerEventType.Enter) {
+ hover = true
+ }
+ .onPointerEvent(PointerEventType.Exit) {
+ hover = false
+ }
+ .pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR)))
+ .background(color)
+ .padding(10.dp)
+ .sizeIn(minWidth = 100.dp),
+ contentAlignment = Alignment.Center,
+ content = content
+ )
+ }
+ }
+
@JvmStatic
fun main(args: Array) {
@@ -108,9 +168,12 @@ Please report any bugs on the forums."""
size = DpSize.Unspecified,
position = WindowPosition(Alignment.Center)
)
+
Window(onCloseRequest = ::exitApplication, state = windowState, title = windowTitle) {
Surface(color = Color.White) {
- welcomeToBeta()
+ welcomeToBeta{
+ exitApplication()
+ }
}
}
From ed49b65c48b39e1322584910f5d7bcadcedcc160 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 20:17:55 +0100
Subject: [PATCH 005/160] Welcome to Beta screen: Colors, Typhography, Locale
---
app/build.gradle.kts | 3 +
app/src/processing/app/ui/WelcomeToBeta.kt | 66 ++++++++++-------
app/src/processing/app/ui/theme/Locale.kt | 31 ++++++++
app/src/processing/app/ui/theme/Theme.kt | 71 +++++++++++++++++++
app/src/processing/app/ui/theme/Typography.kt | 38 ++++++++++
build/shared/lib/languages/PDE.properties | 7 ++
build/shared/lib/languages/PDE_nl.properties | 7 ++
7 files changed, 196 insertions(+), 27 deletions(-)
create mode 100644 app/src/processing/app/ui/theme/Locale.kt
create mode 100644 app/src/processing/app/ui/theme/Theme.kt
create mode 100644 app/src/processing/app/ui/theme/Typography.kt
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 05414e14d..8dd6e88f0 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -38,6 +38,9 @@ sourceSets{
kotlin{
srcDirs("src")
}
+ resources{
+ srcDirs("resources", listOf("languages", "fonts", "theme").map { "../build/shared/lib/$it" })
+ }
}
}
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index 773e81be1..c057deba9 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -5,6 +5,8 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.MaterialTheme.colors
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
@@ -27,10 +29,16 @@ import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import com.formdev.flatlaf.util.SystemInfo
+import processing.app.ui.theme.LocalLocale
+import processing.app.ui.theme.LocalTheme
+import processing.app.ui.theme.Locale
+import processing.app.ui.theme.ProcessingTheme
import java.awt.Cursor
import java.awt.Dimension
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
+import java.io.InputStream
+import java.util.Properties
import javax.swing.JFrame
import javax.swing.SwingUtilities
@@ -38,12 +46,7 @@ import javax.swing.SwingUtilities
class WelcomeToBeta {
companion object{
val windowSize = Dimension(400, 200)
- val windowTitle = "Welcome to Beta"
- val title = "Welcome to the Processing Beta"
- val message = """Thank you for trying out the new version of Processing. We’re very grateful!
-
-Please report any bugs on the forums."""
- val buttonText = "Thank you"
+ val windowTitle = Locale()["beta.window.title"]
@JvmStatic
fun showWelcomeToBeta() {
@@ -57,8 +60,10 @@ Please report any bugs on the forums."""
contentPane.add(ComposePanel().apply {
size = windowSize
setContent {
- Box(modifier = Modifier.padding(top = if(mac) 22.dp else 0.dp)) {
- welcomeToBeta(close)
+ ProcessingTheme {
+ Box(modifier = Modifier.padding(top = if (mac) 22.dp else 0.dp)) {
+ welcomeToBeta(close)
+ }
}
}
})
@@ -79,14 +84,12 @@ Please report any bugs on the forums."""
@Composable
fun welcomeToBeta(close: () -> Unit = {}) {
- // TODO: Add fonts and colors
-
Row(
modifier = Modifier
.padding(20.dp, 10.dp)
- .size(windowSize.width.dp, windowSize.height.dp)
- ,
- horizontalArrangement = Arrangement.spacedBy(20.dp)
+ .size(windowSize.width.dp, windowSize.height.dp),
+ horizontalArrangement = Arrangement
+ .spacedBy(20.dp)
){
Image(
painter = painterResource("logo.svg"),
@@ -97,24 +100,30 @@ Please report any bugs on the forums."""
)
Column(
modifier = Modifier
- .fillMaxHeight(),
- verticalArrangement = Arrangement.spacedBy(20.dp, alignment = Alignment.CenterVertically)
+ .fillMaxHeight(),
+ verticalArrangement = Arrangement
+ .spacedBy(
+ MaterialTheme.typography.subtitle1.lineHeight.value.dp,
+ alignment = Alignment.CenterVertically
+ )
) {
+ val locale = LocalLocale.current
Text(
- title,
- fontSize = 17.sp,
- fontWeight = FontWeight.SemiBold
+ text = locale["beta.title"],
+ style = MaterialTheme.typography.subtitle1,
)
Text(
- message,
- fontSize = 13.sp
+ text = locale["beta.message"]
)
Row {
Spacer(modifier = Modifier.weight(1f))
PDEButton(onClick = {
close()
}) {
- Text(buttonText, color = Color.White)
+ Text(
+ text = locale["beta.button"],
+ color = Color.White
+ )
}
}
}
@@ -123,16 +132,18 @@ Please report any bugs on the forums."""
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PDEButton(onClick: () -> Unit, content: @Composable BoxScope.() -> Unit) {
+ val theme = LocalTheme.current
+
var hover by remember { mutableStateOf(false) }
var clicked by remember { mutableStateOf(false) }
val offset by animateFloatAsState(if (hover) -5f else 5f)
- val color by animateColorAsState(if(clicked) Color.Black else Color.Blue)
+ val color by animateColorAsState(if(clicked) colors.primaryVariant else colors.primary)
Box(modifier = Modifier.padding(end = 5.dp, top = 5.dp)) {
Box(
modifier = Modifier
.offset((-offset).dp, (offset).dp)
- .background(Color.Gray)
+ .background(theme.getColor("toolbar.button.pressed.field"))
.matchParentSize()
)
Box(
@@ -170,12 +181,13 @@ Please report any bugs on the forums."""
)
Window(onCloseRequest = ::exitApplication, state = windowState, title = windowTitle) {
- Surface(color = Color.White) {
- welcomeToBeta{
- exitApplication()
+ ProcessingTheme {
+ Surface(color = colors.background) {
+ welcomeToBeta {
+ exitApplication()
+ }
}
}
-
}
}
}
diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt
new file mode 100644
index 000000000..97940a085
--- /dev/null
+++ b/app/src/processing/app/ui/theme/Locale.kt
@@ -0,0 +1,31 @@
+package processing.app.ui.theme
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
+import java.io.InputStream
+import java.util.*
+
+class Locale : Properties() {
+ init {
+ val locale = java.util.Locale.getDefault()
+ load(ClassLoader.getSystemResourceAsStream("PDE.properties"))
+ load(ClassLoader.getSystemResourceAsStream("PDE_${locale.language}.properties") ?: InputStream.nullInputStream())
+ load(ClassLoader.getSystemResourceAsStream("PDE_${locale.toLanguageTag()}.properties") ?: InputStream.nullInputStream())
+ }
+
+ @Deprecated("Use get instead", ReplaceWith("get(key)"))
+ override fun getProperty(key: String?): String {
+ return super.getProperty(key)
+ }
+ operator fun get(key: String): String = getProperty(key)
+}
+val LocalLocale = compositionLocalOf { Locale() }
+@Composable
+fun LocaleProvider(content: @Composable () -> Unit) {
+ val locale = Locale()
+ // TODO: Listen for languages changes
+ CompositionLocalProvider(LocalLocale provides locale) {
+ content()
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/ui/theme/Theme.kt b/app/src/processing/app/ui/theme/Theme.kt
new file mode 100644
index 000000000..bd2524d64
--- /dev/null
+++ b/app/src/processing/app/ui/theme/Theme.kt
@@ -0,0 +1,71 @@
+package processing.app.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.Colors
+import androidx.compose.material.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
+import androidx.compose.ui.graphics.Color
+import java.io.InputStream
+import java.util.Properties
+
+
+class Theme(themeFile: String? = "") : Properties() {
+ init {
+ load(ClassLoader.getSystemResourceAsStream("theme.txt"))
+ load(ClassLoader.getSystemResourceAsStream(themeFile) ?: InputStream.nullInputStream())
+ }
+ fun getColor(key: String): Color {
+ return Color(getProperty(key).toColorInt())
+ }
+}
+
+val LocalTheme = compositionLocalOf { error("No theme provided") }
+
+@Composable
+fun ProcessingTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable() () -> Unit
+) {
+
+ val theme = Theme()
+ val colors = Colors(
+ primary = theme.getColor("editor.gradient.top"),
+ primaryVariant = theme.getColor("toolbar.button.pressed.field"),
+ secondary = theme.getColor("editor.gradient.bottom"),
+ secondaryVariant = theme.getColor("editor.scrollbar.thumb.pressed.color"),
+ background = theme.getColor("editor.bgcolor"),
+ surface = theme.getColor("editor.bgcolor"),
+ error = theme.getColor("status.error.bgcolor"),
+ onPrimary = theme.getColor("toolbar.button.pressed.field"),
+ onSecondary = theme.getColor("toolbar.button.pressed.field"),
+ onBackground = theme.getColor("editor.fgcolor"),
+ onSurface = theme.getColor("editor.fgcolor"),
+ onError = theme.getColor("status.error.fgcolor"),
+ isLight = theme.getProperty("laf.mode").equals("light")
+ )
+
+ CompositionLocalProvider(LocalTheme provides theme) {
+ LocaleProvider {
+ MaterialTheme(
+ colors = colors,
+ typography = Typography,
+ content = content
+ )
+ }
+ }
+}
+
+fun String.toColorInt(): Int {
+ if (this[0] == '#') {
+ var color = substring(1).toLong(16)
+ if (length == 7) {
+ color = color or 0x00000000ff000000L
+ } else if (length != 9) {
+ throw IllegalArgumentException("Unknown color")
+ }
+ return color.toInt()
+ }
+ throw IllegalArgumentException("Unknown color")
+}
\ No newline at end of file
diff --git a/app/src/processing/app/ui/theme/Typography.kt b/app/src/processing/app/ui/theme/Typography.kt
new file mode 100644
index 000000000..5d87c490e
--- /dev/null
+++ b/app/src/processing/app/ui/theme/Typography.kt
@@ -0,0 +1,38 @@
+package processing.app.ui.theme
+
+import androidx.compose.material.MaterialTheme.typography
+import androidx.compose.material.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.platform.Font
+import androidx.compose.ui.unit.sp
+
+val processingFont = FontFamily(
+ Font(
+ resource = "ProcessingSans-Regular.ttf",
+ weight = FontWeight.Normal,
+ style = FontStyle.Normal
+ ),
+ Font(
+ resource = "ProcessingSans-Bold.ttf",
+ weight = FontWeight.Bold,
+ style = FontStyle.Normal
+ )
+)
+
+val Typography = Typography(
+ body1 = TextStyle(
+ fontFamily = processingFont,
+ fontWeight = FontWeight.Normal,
+ fontSize = 13.sp,
+ lineHeight = 16.sp
+ ),
+ subtitle1 = TextStyle(
+ fontFamily = processingFont,
+ fontWeight = FontWeight.Bold,
+ fontSize = 16.sp,
+ lineHeight = 20.sp
+ )
+)
\ No newline at end of file
diff --git a/build/shared/lib/languages/PDE.properties b/build/shared/lib/languages/PDE.properties
index 02f98473e..be680c159 100644
--- a/build/shared/lib/languages/PDE.properties
+++ b/build/shared/lib/languages/PDE.properties
@@ -614,6 +614,13 @@ update_check.updates_available.core = A new version of Processing is available,\
update_check.updates_available.contributions = There are updates available for some of the installed contributions,\nwould you like to open the the Contribution Manager now?
+# ---------------------------------------
+# Beta
+beta.window.title = Welcome to Beta
+beta.title = Welcome to the Processing Beta
+beta.message = Thank you for trying out the new version of Processing. We?re very grateful!\n\nPlease report any bugs on the forums.
+beta.button = Got it!
+
# ---------------------------------------
# Color Chooser
diff --git a/build/shared/lib/languages/PDE_nl.properties b/build/shared/lib/languages/PDE_nl.properties
index 9b9527517..f1ac08b5e 100644
--- a/build/shared/lib/languages/PDE_nl.properties
+++ b/build/shared/lib/languages/PDE_nl.properties
@@ -315,6 +315,13 @@ update_check = Update
update_check.updates_available.core = Een nieuwe versie van Processing is beschikbaar,\nwilt u de Processing download pagina bezoeken?
update_check.updates_available.contributions = Er zijn updates beschikbaar voor sommige van de door u geïnstalleerde bijdragen,\nwilt u nu de Bijdragen Manager openen?
+# ---------------------------------------
+# Beta
+beta.window.title = Welkom bij Beta
+beta.title = Welkom bij de Processing Beta
+beta.message = Bedankt dat je de nieuwe versie van Processing uitprobeert. We zijn je zeer dankbaar!\n\nMeld eventuele bugs alsjeblieft op de forums.
+beta.button = Okee!
+
# ---------------------------------------
# Color Chooser
From 67da3ac20573f9806e4a64b80e2e1ce88c5d288a Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 20:53:15 +0100
Subject: [PATCH 006/160] Welcome to Beta screen: Preferences
---
.../app/{contrib/ui => }/Preferences.kt | 34 ++++++------
.../app/contrib/ui/ContributionManager.kt | 14 +----
app/src/processing/app/ui/WelcomeToBeta.kt | 2 +-
app/src/processing/app/ui/theme/Locale.kt | 17 ++++--
app/src/processing/app/ui/theme/Theme.kt | 52 ++++++++++---------
5 files changed, 63 insertions(+), 56 deletions(-)
rename app/src/processing/app/{contrib/ui => }/Preferences.kt (69%)
diff --git a/app/src/processing/app/contrib/ui/Preferences.kt b/app/src/processing/app/Preferences.kt
similarity index 69%
rename from app/src/processing/app/contrib/ui/Preferences.kt
rename to app/src/processing/app/Preferences.kt
index b344e1cb7..c5645c9bb 100644
--- a/app/src/processing/app/contrib/ui/Preferences.kt
+++ b/app/src/processing/app/Preferences.kt
@@ -1,11 +1,10 @@
-package processing.app.contrib.ui
+package processing.app
import androidx.compose.runtime.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import processing.app.Base
-import processing.app.Platform
import java.io.File
+import java.io.InputStream
import java.nio.file.*
import java.util.Properties
@@ -13,10 +12,13 @@ import java.util.Properties
const val PREFERENCES_FILE_NAME = "preferences.txt"
const val DEFAULTS_FILE_NAME = "defaults.txt"
+fun PlatformStart(){
+ Platform.inst ?: Platform.init()
+}
@Composable
fun loadPreferences(): Properties{
- Platform.init()
+ PlatformStart()
val settingsFolder = Platform.getSettingsFolder()
val preferencesFile = settingsFolder.resolve(PREFERENCES_FILE_NAME)
@@ -24,20 +26,12 @@ fun loadPreferences(): Properties{
if(!preferencesFile.exists()){
preferencesFile.createNewFile()
}
- val watched = watchFile(preferencesFile)
+ watchFile(preferencesFile)
- val preferences by remember {
- mutableStateOf(Properties())
+ return Properties().apply {
+ load(ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME) ?: InputStream.nullInputStream())
+ load(preferencesFile.inputStream())
}
-
- LaunchedEffect(watched){
- val defaults = Base::class.java.getResourceAsStream("/lib/${DEFAULTS_FILE_NAME}") ?: return@LaunchedEffect
-
- preferences.load(defaults)
- preferences.load(preferencesFile.inputStream())
- }
-
- return preferences
}
@Composable
@@ -68,4 +62,12 @@ fun watchFile(file: File): Any? {
}
}
return event
+}
+val LocalPreferences = compositionLocalOf { error("No preferences provided") }
+@Composable
+fun PreferencesProvider(content: @Composable () -> Unit){
+ val preferences = loadPreferences()
+ CompositionLocalProvider(LocalPreferences provides preferences){
+ content()
+ }
}
\ No newline at end of file
diff --git a/app/src/processing/app/contrib/ui/ContributionManager.kt b/app/src/processing/app/contrib/ui/ContributionManager.kt
index a057e76df..2ad472159 100644
--- a/app/src/processing/app/contrib/ui/ContributionManager.kt
+++ b/app/src/processing/app/contrib/ui/ContributionManager.kt
@@ -12,8 +12,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.ComposePanel
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.text.font.FontWeight
@@ -25,6 +23,7 @@ import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import kotlinx.serialization.Serializable
import processing.app.Platform
+import processing.app.loadPreferences
import java.net.URL
import java.util.*
import javax.swing.JFrame
@@ -33,16 +32,7 @@ import kotlin.io.path.*
fun main() = application {
- val active = remember { mutableStateOf(true) }
- if(!active.value){
- Window(onCloseRequest = ::exitApplication) {
-
- }
- return@application
- }
- Window(
- onCloseRequest = { active.value = false },
- ) {
+ Window(onCloseRequest = ::exitApplication) {
contributionsManager()
}
}
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index c057deba9..7c75bb803 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -122,7 +122,7 @@ class WelcomeToBeta {
}) {
Text(
text = locale["beta.button"],
- color = Color.White
+ color = colors.onPrimary
)
}
}
diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt
index 97940a085..3516b28a3 100644
--- a/app/src/processing/app/ui/theme/Locale.kt
+++ b/app/src/processing/app/ui/theme/Locale.kt
@@ -3,15 +3,21 @@ package processing.app.ui.theme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
+import processing.app.LocalPreferences
+import processing.app.Platform
+import processing.app.PlatformStart
+import processing.app.watchFile
+import java.io.File
import java.io.InputStream
import java.util.*
-class Locale : Properties() {
+class Locale(language: String = "") : Properties() {
init {
val locale = java.util.Locale.getDefault()
load(ClassLoader.getSystemResourceAsStream("PDE.properties"))
load(ClassLoader.getSystemResourceAsStream("PDE_${locale.language}.properties") ?: InputStream.nullInputStream())
load(ClassLoader.getSystemResourceAsStream("PDE_${locale.toLanguageTag()}.properties") ?: InputStream.nullInputStream())
+ load(ClassLoader.getSystemResourceAsStream("PDE_${language}.properties") ?: InputStream.nullInputStream())
}
@Deprecated("Use get instead", ReplaceWith("get(key)"))
@@ -23,8 +29,13 @@ class Locale : Properties() {
val LocalLocale = compositionLocalOf { Locale() }
@Composable
fun LocaleProvider(content: @Composable () -> Unit) {
- val locale = Locale()
- // TODO: Listen for languages changes
+ PlatformStart()
+
+ val settingsFolder = Platform.getSettingsFolder()
+ val languageFile = File(settingsFolder, "language.txt")
+ watchFile(languageFile)
+
+ val locale = Locale(languageFile.readText().substring(0, 2))
CompositionLocalProvider(LocalLocale provides locale) {
content()
}
diff --git a/app/src/processing/app/ui/theme/Theme.kt b/app/src/processing/app/ui/theme/Theme.kt
index bd2524d64..735d8e5b2 100644
--- a/app/src/processing/app/ui/theme/Theme.kt
+++ b/app/src/processing/app/ui/theme/Theme.kt
@@ -7,6 +7,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
+import processing.app.LocalPreferences
+import processing.app.PreferencesProvider
import java.io.InputStream
import java.util.Properties
@@ -28,31 +30,33 @@ fun ProcessingTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
+ PreferencesProvider {
+ val preferences = LocalPreferences.current
+ val theme = Theme(preferences.getProperty("theme"))
+ val colors = Colors(
+ primary = theme.getColor("editor.gradient.top"),
+ primaryVariant = theme.getColor("toolbar.button.pressed.field"),
+ secondary = theme.getColor("editor.gradient.bottom"),
+ secondaryVariant = theme.getColor("editor.scrollbar.thumb.pressed.color"),
+ background = theme.getColor("editor.bgcolor"),
+ surface = theme.getColor("editor.bgcolor"),
+ error = theme.getColor("status.error.bgcolor"),
+ onPrimary = theme.getColor("toolbar.button.enabled.field"),
+ onSecondary = theme.getColor("toolbar.button.enabled.field"),
+ onBackground = theme.getColor("editor.fgcolor"),
+ onSurface = theme.getColor("editor.fgcolor"),
+ onError = theme.getColor("status.error.fgcolor"),
+ isLight = theme.getProperty("laf.mode").equals("light")
+ )
- val theme = Theme()
- val colors = Colors(
- primary = theme.getColor("editor.gradient.top"),
- primaryVariant = theme.getColor("toolbar.button.pressed.field"),
- secondary = theme.getColor("editor.gradient.bottom"),
- secondaryVariant = theme.getColor("editor.scrollbar.thumb.pressed.color"),
- background = theme.getColor("editor.bgcolor"),
- surface = theme.getColor("editor.bgcolor"),
- error = theme.getColor("status.error.bgcolor"),
- onPrimary = theme.getColor("toolbar.button.pressed.field"),
- onSecondary = theme.getColor("toolbar.button.pressed.field"),
- onBackground = theme.getColor("editor.fgcolor"),
- onSurface = theme.getColor("editor.fgcolor"),
- onError = theme.getColor("status.error.fgcolor"),
- isLight = theme.getProperty("laf.mode").equals("light")
- )
-
- CompositionLocalProvider(LocalTheme provides theme) {
- LocaleProvider {
- MaterialTheme(
- colors = colors,
- typography = Typography,
- content = content
- )
+ CompositionLocalProvider(LocalTheme provides theme) {
+ LocaleProvider {
+ MaterialTheme(
+ colors = colors,
+ typography = Typography,
+ content = content
+ )
+ }
}
}
}
From 00c57607d1f5750361bc9dd0af3b95145b13f883 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 22:47:58 +0100
Subject: [PATCH 007/160] Logging cleanup
---
app/{src => ant}/processing/app/Messages.java | 0
app/src/processing/app/Base.java | 10 +-
app/src/processing/app/Library.java | 23 +-
app/src/processing/app/Messages.kt | 282 ++++++++++++++++++
app/src/processing/app/exec/StreamPump.java | 4 +-
.../app/syntax/im/InputMethodSupport.java | 8 +-
app/src/processing/app/ui/EditorConsole.java | 4 +-
.../processing/mode/java/CompletionPanel.java | 2 +-
.../processing/mode/java/PreprocService.java | 14 +-
.../processing/mode/java/runner/Runner.java | 12 +-
10 files changed, 320 insertions(+), 39 deletions(-)
rename app/{src => ant}/processing/app/Messages.java (100%)
create mode 100644 app/src/processing/app/Messages.kt
diff --git a/app/src/processing/app/Messages.java b/app/ant/processing/app/Messages.java
similarity index 100%
rename from app/src/processing/app/Messages.java
rename to app/ant/processing/app/Messages.java
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index a5b3ac7c0..4690c6946 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -563,14 +563,12 @@ public class Base {
cl.downloadAvailableList(this, new ContribProgress(null));
long t9 = System.currentTimeMillis();
- if (DEBUG) {
- System.out.println("core modes: " + (t2b-t2) +
- ", contrib modes: " + (t2c-t2b) +
- ", contrib ex: " + (t2c-t2b));
- System.out.println("base took " + (t2-t1) + " " + (t3-t2) + " " + (t4-t3) +
+ Messages.log("core modes: " + (t2b-t2) +
+ ", contrib modes: " + (t2c-t2b) +
+ ", contrib ex: " + (t2c-t2b));
+ Messages.log("base took " + (t2-t1) + " " + (t3-t2) + " " + (t4-t3) +
" " + (t5-t4) + " t6-t5=" + (t6-t5) + " " + (t7-t6) +
" handleNew=" + (t8-t7) + " " + (t9-t8) + " ms");
- }
}
diff --git a/app/src/processing/app/Library.java b/app/src/processing/app/Library.java
index dc8269eeb..e92ee8496 100644
--- a/app/src/processing/app/Library.java
+++ b/app/src/processing/app/Library.java
@@ -330,6 +330,7 @@ public class Library extends LocalContribution {
* imports to specific libraries.
* @param importToLibraryTable mapping from package names to Library objects
*/
+ static boolean instruced = false;
// public void addPackageList(HashMap importToLibraryTable) {
public void addPackageList(Map> importToLibraryTable) {
// PApplet.println(packages);
@@ -342,18 +343,20 @@ public class Library extends LocalContribution {
libraries = new ArrayList<>();
importToLibraryTable.put(pkg, libraries);
} else {
- if (Base.DEBUG) {
- System.err.println("The library found in");
- System.err.println(getPath());
- System.err.println("conflicts with");
+ if(!instruced) {
+ instruced = true;
+ Messages.err("The library found in");
+ Messages.err(getPath());
+ Messages.err("conflicts with");
for (Library library : libraries) {
- System.err.println(library.getPath());
+ Messages.err(library.getPath());
}
- System.err.println("which already define(s) the package " + pkg);
- System.err.println("If you have a line in your sketch that reads");
- System.err.println("import " + pkg + ".*;");
- System.err.println("Then you'll need to first remove one of those libraries.");
- System.err.println();
+ Messages.err("which already define(s) the package " + pkg);
+ Messages.err("If you have a line in your sketch that reads");
+ Messages.err("import " + pkg + ".*;");
+ Messages.err("Then you'll need to first remove one of those libraries.");
+ }else{
+ Messages.err("\tPackage ("+pkg+")\t conflict found in [" + name + "] with libraries: " + libraries.stream().map(Library::getName).reduce((a, b) -> a + ", " + b).orElse(""));
}
}
libraries.add(this);
diff --git a/app/src/processing/app/Messages.kt b/app/src/processing/app/Messages.kt
new file mode 100644
index 000000000..cae54e6e9
--- /dev/null
+++ b/app/src/processing/app/Messages.kt
@@ -0,0 +1,282 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2015 The Processing Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+package processing.app
+
+import processing.app.ui.Toolkit
+import java.awt.EventQueue
+import java.awt.Frame
+import java.io.PrintWriter
+import java.io.StringWriter
+import javax.swing.JFrame
+import javax.swing.JOptionPane
+
+class Messages {
+ companion object {
+ /**
+ * "No cookie for you" type messages. Nothing fatal or all that
+ * much of a bummer, but something to notify the user about.
+ */
+ @JvmStatic
+ fun showMessage(title: String = "Message", message: String) {
+ if (Base.isCommandLine()) {
+ println("$title: $message")
+ } else {
+ JOptionPane.showMessageDialog(
+ Frame(), message, title,
+ JOptionPane.INFORMATION_MESSAGE
+ )
+ }
+ }
+
+
+ /**
+ * Non-fatal error message with optional stack trace side dish.
+ */
+ /**
+ * Non-fatal error message.
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun showWarning(title: String = "Warning", message: String, e: Throwable? = null) {
+ if (Base.isCommandLine()) {
+ println("$title: $message")
+ } else {
+ JOptionPane.showMessageDialog(
+ Frame(), message, title,
+ JOptionPane.WARNING_MESSAGE
+ )
+ }
+ e?.printStackTrace()
+ }
+
+ /**
+ * Non-fatal error message with two levels of formatting.
+ * Unlike the others, this is non-blocking and will run later on the EDT.
+ */
+ @JvmStatic
+ fun showWarningTiered(
+ title: String,
+ primary: String, secondary: String,
+ e: Throwable?
+ ) {
+ if (Base.isCommandLine()) {
+ // TODO All these messages need to be handled differently for
+ // proper parsing on the command line. Many have \n in them.
+ println("$title: $primary\n$secondary")
+ } else {
+ EventQueue.invokeLater {
+ JOptionPane.showMessageDialog(
+ JFrame(),
+ Toolkit.formatMessage(primary, secondary),
+ title, JOptionPane.WARNING_MESSAGE
+ )
+ }
+ }
+ e?.printStackTrace()
+ }
+
+
+ /**
+ * Show an error message that's actually fatal to the program.
+ * This is an error that can't be recovered. Use showWarning()
+ * for errors that allow P5 to continue running.
+ */
+ @JvmStatic
+ fun showError(title: String = "Error", message: String, e: Throwable?) {
+ if (Base.isCommandLine()) {
+ System.err.println("$title: $message")
+ } else {
+ JOptionPane.showMessageDialog(
+ Frame(), message, title,
+ JOptionPane.ERROR_MESSAGE
+ )
+ }
+ e?.printStackTrace()
+ System.exit(1)
+ }
+
+
+ /**
+ * Warning window that includes the stack trace.
+ */
+ @JvmStatic
+ fun showTrace(
+ title: String?,
+ message: String,
+ t: Throwable?,
+ fatal: Boolean
+ ) {
+ val title = title ?: if (fatal) "Error" else "Warning"
+
+ if (Base.isCommandLine()) {
+ System.err.println("$title: $message")
+ t?.printStackTrace()
+ } else {
+ val sw = StringWriter()
+ t!!.printStackTrace(PrintWriter(sw))
+
+ JOptionPane.showMessageDialog(
+ Frame(), // first clears to the next line
+ // second is a shorter height blank space before the trace
+ Toolkit.formatMessage("$message $sw"),
+ title,
+ if (fatal) JOptionPane.ERROR_MESSAGE else JOptionPane.WARNING_MESSAGE
+ )
+
+ if (fatal) {
+ System.exit(1)
+ }
+ }
+ }
+
+ @JvmStatic
+ fun showYesNoQuestion(
+ editor: Frame?, title: String?,
+ primary: String?, secondary: String?
+ ): Int {
+ if (!Platform.isMacOS()) {
+ return JOptionPane.showConfirmDialog(
+ editor,
+ Toolkit.formatMessage(primary, secondary), //"" +
+ //"" + primary + "" +
+ //" " + secondary,
+ title,
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE
+ )
+ } else {
+ val result = showCustomQuestion(
+ editor, title, primary, secondary,
+ 0, "Yes", "No"
+ )
+ return if (result == 0) {
+ JOptionPane.YES_OPTION
+ } else if (result == 1) {
+ JOptionPane.NO_OPTION
+ } else {
+ JOptionPane.CLOSED_OPTION
+ }
+ }
+ }
+
+
+ /**
+ * @param highlight A valid array index for options[] that specifies the
+ * default (i.e. safe) choice.
+ * @return The (zero-based) index of the selected value, -1 otherwise.
+ */
+ @JvmStatic
+ fun showCustomQuestion(
+ editor: Frame?, title: String?,
+ primary: String?, secondary: String?,
+ highlight: Int, vararg options: String
+ ): Int {
+ val result: Any
+ if (!Platform.isMacOS()) {
+ return JOptionPane.showOptionDialog(
+ editor,
+ Toolkit.formatMessage(primary, secondary), title,
+ JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+ options, options[highlight]
+ )
+ } else {
+ val pane =
+ JOptionPane(
+ Toolkit.formatMessage(primary, secondary),
+ JOptionPane.QUESTION_MESSAGE
+ )
+
+ pane.options = options
+
+ // highlight the safest option ala apple hig
+ pane.initialValue = options[highlight]
+
+ val dialog = pane.createDialog(editor, null)
+ dialog.isVisible = true
+
+ result = pane.value
+ }
+ for (i in options.indices) {
+ if (result != null && result == options[i]) return i
+ }
+ return -1
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+ @JvmStatic
+ @Deprecated("Use log() instead")
+ fun log(from: Any, message: String) {
+ if (Base.DEBUG) {
+ val callingClass = Throwable()
+ .stackTrace[2]
+ .className
+ .formatClassName()
+ println("$callingClass: $message")
+ }
+ }
+
+ @JvmStatic
+ fun log(message: String?) {
+ if (Base.DEBUG) {
+ val callingClass = Throwable()
+ .stackTrace[2]
+ .className
+ .formatClassName()
+ println("$callingClass$message")
+ }
+ }
+
+ @JvmStatic
+ fun logf(message: String?, vararg args: Any?) {
+ if (Base.DEBUG) {
+ val callingClass = Throwable()
+ .stackTrace[2]
+ .className
+ .formatClassName()
+ System.out.printf("$callingClass$message", *args)
+ }
+ }
+
+ @JvmStatic
+ @JvmOverloads
+ fun err(message: String?, e: Throwable? = null) {
+ if (Base.DEBUG) {
+ if (message != null) {
+ val callingClass = Throwable()
+ .stackTrace[4]
+ .className
+ .formatClassName()
+ System.err.println("$callingClass$message")
+ }
+ e?.printStackTrace()
+ }
+ }
+ }
+}
+
+// Helper functions to give the base classes a color
+fun String.formatClassName() = this
+ .replace("processing.", "")
+ .replace(".", "/")
+ .padEnd(40)
+ .colorizePathParts()
+fun String.colorizePathParts() = split("/").joinToString("/") { part ->
+ "\u001B[${31 + (part.hashCode() and 0x7).rem(6)}m$part\u001B[0m"
+}
\ No newline at end of file
diff --git a/app/src/processing/app/exec/StreamPump.java b/app/src/processing/app/exec/StreamPump.java
index 130a74afd..29786102c 100644
--- a/app/src/processing/app/exec/StreamPump.java
+++ b/app/src/processing/app/exec/StreamPump.java
@@ -13,6 +13,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import processing.app.Base;
+import processing.app.Messages;
/**
@@ -79,8 +80,7 @@ public class StreamPump implements Runnable {
}
} catch (final IOException e) {
if (Base.DEBUG) {
- System.err.println("StreamPump: " + name);
- e.printStackTrace(System.err);
+ Messages.err("StreamPump: " + name, e);
// removing for 0190, but need a better way to handle these
throw new RuntimeException("Inside " + this + " for " + name, e);
}
diff --git a/app/src/processing/app/syntax/im/InputMethodSupport.java b/app/src/processing/app/syntax/im/InputMethodSupport.java
index 391b96b97..e3323fa11 100644
--- a/app/src/processing/app/syntax/im/InputMethodSupport.java
+++ b/app/src/processing/app/syntax/im/InputMethodSupport.java
@@ -79,9 +79,7 @@ public class InputMethodSupport implements InputMethodRequests, InputMethodListe
@Override
public Rectangle getTextLocation(TextHitInfo offset) {
- if (Base.DEBUG) {
- Messages.log("#Called getTextLocation:" + offset);
- }
+ Messages.log("#Called getTextLocation:" + offset);
int line = textArea.getCaretLine();
int offsetX = textArea.getCaretPosition() - textArea.getLineStartOffset(line);
// '+1' mean textArea.lineToY(line) + textArea.getPainter().getFontMetrics().getHeight().
@@ -238,9 +236,7 @@ public class InputMethodSupport implements InputMethodRequests, InputMethodListe
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
FontRenderContext frc = g2d.getFontRenderContext();
- if (Base.DEBUG) {
- Messages.log("debug: FontRenderContext is Antialiased = " + frc.getAntiAliasingHint());
- }
+ Messages.log("debug: FontRenderContext is Antialiased = " + frc.getAntiAliasingHint());
return new TextLayout(composedTextString.getIterator(), frc);
}
diff --git a/app/src/processing/app/ui/EditorConsole.java b/app/src/processing/app/ui/EditorConsole.java
index 14be32d68..c8c40ee48 100644
--- a/app/src/processing/app/ui/EditorConsole.java
+++ b/app/src/processing/app/ui/EditorConsole.java
@@ -276,7 +276,9 @@ public class EditorConsole extends JScrollPane {
// components, causing deadlock. Updates are buffered to the console and
// displayed at regular intervals on Swing's event-dispatching thread.
// (patch by David Mellis)
- consoleDoc.appendString(what, err ? errStyle : stdStyle);
+ // Remove ANSI escape codes from the text before adding it to the console
+ String clean = what.replaceAll("\u001B\\[[0-9;]*m", "");
+ consoleDoc.appendString(clean, err ? errStyle : stdStyle);
}
}
diff --git a/java/src/processing/mode/java/CompletionPanel.java b/java/src/processing/mode/java/CompletionPanel.java
index bda85d75e..2ba1eb29e 100644
--- a/java/src/processing/mode/java/CompletionPanel.java
+++ b/java/src/processing/mode/java/CompletionPanel.java
@@ -287,7 +287,7 @@ public class CompletionPanel {
int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x1 = x - 1;
if (x >= s.length() || x < 0)
return null; //TODO: Does this check cause problems? Verify.
- if (Base.DEBUG) System.out.print(" x char: " + s.charAt(x));
+ Messages.log(" x char: " + s.charAt(x));
String word = String.valueOf(s.charAt(x));
if (s.trim().length() == 1) {
diff --git a/java/src/processing/mode/java/PreprocService.java b/java/src/processing/mode/java/PreprocService.java
index f70536294..4f9150561 100644
--- a/java/src/processing/mode/java/PreprocService.java
+++ b/java/src/processing/mode/java/PreprocService.java
@@ -117,7 +117,7 @@ public class PreprocService {
running = true;
PreprocSketch prevResult = null;
CompletableFuture> runningCallbacks = null;
- Messages.log("PPS: Hi!");
+ Messages.log("Hi!");
while (running) {
try {
try {
@@ -127,7 +127,7 @@ public class PreprocService {
break;
}
- Messages.log("PPS: Starting");
+ Messages.log("Starting");
prevResult = preprocessSketch(prevResult);
@@ -143,7 +143,7 @@ public class PreprocService {
synchronized (requestLock) {
if (requestQueue.isEmpty()) {
runningCallbacks = lastCallback;
- Messages.log("PPS: Done");
+ Messages.log("Done");
preprocessingTask.complete(prevResult);
}
}
@@ -151,7 +151,7 @@ public class PreprocService {
Messages.err("problem in preprocessor service loop", e);
}
}
- Messages.log("PPS: Bye!");
+ Messages.log("Bye!");
}
/**
@@ -188,7 +188,7 @@ public class PreprocService {
* Indicate to this service that the sketch libraries have changed.
*/
public void notifyLibrariesChanged() {
- Messages.log("PPS: notified libraries changed");
+ Messages.log("notified libraries changed");
librariesChanged.set(true);
notifySketchChanged();
}
@@ -197,7 +197,7 @@ public class PreprocService {
* Indicate to this service that the folder housing sketch code has changed.
*/
public void notifyCodeFolderChanged() {
- Messages.log("PPS: notified code folder changed");
+ Messages.log("notified code folder changed");
codeFolderChanged.set(true);
notifySketchChanged();
}
@@ -216,7 +216,7 @@ public class PreprocService {
.thenAcceptBothAsync(lastCallback, (ps, a) -> callback.accept(ps))
// Make sure exception in callback won't cancel whole callback chain
.handleAsync((res, e) -> {
- if (e != null) Messages.err("PPS: exception in callback", e);
+ if (e != null) Messages.err("exception in callback", e);
return res;
});
return lastCallback;
diff --git a/java/src/processing/mode/java/runner/Runner.java b/java/src/processing/mode/java/runner/Runner.java
index 0e29e18a1..b4dc51770 100644
--- a/java/src/processing/mode/java/runner/Runner.java
+++ b/java/src/processing/mode/java/runner/Runner.java
@@ -253,19 +253,19 @@ public class Runner implements MessageConsumer {
// while (!available) {
while (true) {
try {
- Messages.log(getClass().getName() + " attempting to attach to VM");
+ Messages.log("attempting to attach to VM");
synchronized (cancelLock) {
vm = connector.attach(arguments);
if (cancelled && vm != null) {
// cancelled and connected to the VM, handle closing now
- Messages.log(getClass().getName() + " aborting, launch cancelled");
+ Messages.log("aborting, launch cancelled");
close();
return false;
}
}
// vm = connector.attach(arguments);
if (vm != null) {
- Messages.log(getClass().getName() + " attached to the VM");
+ Messages.log("attached to the VM");
// generateTrace();
// available = true;
return true;
@@ -273,17 +273,17 @@ public class Runner implements MessageConsumer {
} catch (ConnectException ce) {
// This will fire ConnectException (socket not available) until
// the VM finishes starting up and opens its socket for us.
- Messages.log(getClass().getName() + " socket for VM not ready");
+ Messages.log("socket for VM not ready");
// System.out.println("waiting");
// e.printStackTrace();
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
- Messages.err(getClass().getName() + " interrupted", ie);
+ Messages.err("interrupted", ie);
// ie.printStackTrace(sketchErr);
}
} catch (IOException e) {
- Messages.err(getClass().getName() + " while attaching to VM", e);
+ Messages.err("while attaching to VM", e);
}
}
// } catch (IOException exc) {
From 0483e2e83b8c06e458e5ecc2f3e5bcf5f8c71c8f Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 23:29:13 +0100
Subject: [PATCH 008/160] Welcome to Beta screen: Locale fix
---
app/src/processing/app/ui/WelcomeToBeta.kt | 4 ++--
app/src/processing/app/ui/theme/Locale.kt | 9 ++++++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt
index 7c75bb803..ddffd42d3 100644
--- a/app/src/processing/app/ui/WelcomeToBeta.kt
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -91,9 +91,10 @@ class WelcomeToBeta {
horizontalArrangement = Arrangement
.spacedBy(20.dp)
){
+ val locale = LocalLocale.current
Image(
painter = painterResource("logo.svg"),
- contentDescription = "Processing Logo",
+ contentDescription = locale["beta.logo"],
modifier = Modifier
.align(Alignment.CenterVertically)
.size(100.dp, 100.dp)
@@ -107,7 +108,6 @@ class WelcomeToBeta {
alignment = Alignment.CenterVertically
)
) {
- val locale = LocalLocale.current
Text(
text = locale["beta.title"],
style = MaterialTheme.typography.subtitle1,
diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt
index 3516b28a3..254c0946c 100644
--- a/app/src/processing/app/ui/theme/Locale.kt
+++ b/app/src/processing/app/ui/theme/Locale.kt
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import processing.app.LocalPreferences
+import processing.app.Messages
import processing.app.Platform
import processing.app.PlatformStart
import processing.app.watchFile
@@ -21,10 +22,12 @@ class Locale(language: String = "") : Properties() {
}
@Deprecated("Use get instead", ReplaceWith("get(key)"))
- override fun getProperty(key: String?): String {
- return super.getProperty(key)
+ override fun getProperty(key: String?, default: String): String {
+ val value = super.getProperty(key, default)
+ if(value == default) Messages.log("Missing translation for $key")
+ return value
}
- operator fun get(key: String): String = getProperty(key)
+ operator fun get(key: String): String = getProperty(key, key)
}
val LocalLocale = compositionLocalOf { Locale() }
@Composable
From 0cec8c9dda394bfe82c6e5b197040f0f2f2ac5f7 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 23:29:33 +0100
Subject: [PATCH 009/160] Create defaults.txt
---
app/src/main/resources/defaults.txt | 309 ++++++++++++++++++++++++++++
1 file changed, 309 insertions(+)
create mode 100644 app/src/main/resources/defaults.txt
diff --git a/app/src/main/resources/defaults.txt b/app/src/main/resources/defaults.txt
new file mode 100644
index 000000000..6e3e00f0d
--- /dev/null
+++ b/app/src/main/resources/defaults.txt
@@ -0,0 +1,309 @@
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# DO NOT MAKE CHANGES TO THIS FILE!!!
+
+# These are the default preferences. If you want to modify
+# them directly, use the per-user local version of the file:
+
+# Users -> [username] -> AppData -> Roaming ->
+# Processing -> preferences.txt (on Windows 10)
+
+# ~/Library -> Processing -> preferences.txt (on macOS)
+
+# ~/.config/processing -> preferences.txt (on Linux)
+
+# The exact location of your preferences file can be found at
+# the bottom of the Preferences window inside Processing.
+
+# Because AppData and Application Data may be considered
+# hidden or system folders on Windows, you'll have to ensure
+# that they're visible in order to get at preferences.txt
+
+# You'll have problems running Processing if you incorrectly
+# modify lines in this file. It will probably not start at all.
+
+# AGAIN, DO NOT ALTER THIS FILE! I'M ONLY YELLING BECAUSE I LOVE YOU!
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# If you don't want users to have their sketchbook default to
+# "My Documents/Processing" on Windows and "Documents/Processing" on OS X,
+# set this to another path that will be used by default.
+# Note that this path must exist already otherwise it won't see
+# the sketchbook folder, and will instead assume the sketchbook
+# has gone missing, and that it should instead use the default.
+# In 4.0, the location has changed.
+#sketchbook.path.four=
+
+# Whether or not to show the Welcome screen for 4.0
+# (It's always available under Help → Welcome)
+welcome.four.show = true
+welcome.four.seen = false
+
+# Set 'true' for the default behavior before 4.0, where the
+# main tab must have the same name as the sketch folder
+editor.sync_folder_and_filename = true
+
+# By default, contributions are moved to backup folders when
+# they are removed or replaced. The backups can be found at
+# sketchbook/libraries/old, sketchbook/tools/old, and sketchbook/modes/old
+
+# true to backup contributions when "Remove" button is pressed
+contribution.backup.on_remove = true
+# true to backup contributions when installing a newer version
+contribution.backup.on_install = true
+
+recent.count = 10
+
+# Default to the native (AWT) file selector where possible
+chooser.files.native = true
+# We were shutting this off on macOS because it broke Copy/Paste:
+# https://github.com/processing/processing/issues/1035
+# But removing again for 4.0 alpha 5, because the JFileChooser is awful,
+# and worse on Big Sur, so a bigger problem than the Copy/Paste issue.
+# https://github.com/processing/processing4/issues/77
+#chooser.files.native.macos = false
+
+# set to 'lab' to interpolate theme gradients using L*a*b* color space
+theme.gradient.method = rgb
+
+
+# by default, check the processing server for any updates
+# (please avoid disabling, this also helps us know basic numbers
+# on how many people are using Processing)
+update.check = true
+
+# on windows, automatically associate .pde files with processing.exe
+platform.auto_file_type_associations = true
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# default size for the main window
+editor.window.width.default = 700
+editor.window.height.default = 600
+
+editor.window.width.min = 400
+editor.window.height.min = 500
+# tested as approx 440 on OS X
+editor.window.height.min.macos = 450
+# tested to be 515 on Windows XP, this leaves some room
+editor.window.height.min.windows = 530
+# tested with Raspberry Pi display
+editor.window.height.min.linux = 480
+
+# scaling for the interface (to handle Windows and Linux HiDPI displays)
+editor.zoom = 100%
+# automatically set based on system dpi (only helps on Windows)
+editor.zoom.auto = true
+
+# Use the default monospace font included in lib/fonts.
+# (As of Processing 4 alpha 5, that's Source Code Pro)
+editor.font.family = processing.mono
+editor.font.size = 12
+
+# To reset everyone's default, replaced editor.antialias with editor.smooth
+# for 2.1. Fonts are unusably gross on OS X (and Linux) w/o smoothing and
+# the Oracle JVM, and many longtime users have anti-aliasing turned off.
+editor.smooth = true
+
+# blink the caret by default
+editor.caret.blink = true
+# change to true to use a block (instead of a bar)
+editor.caret.block = false
+
+# enable ctrl-ins, shift-ins, shift-delete for cut/copy/paste
+# on windows and linux, but disable on the mac
+editor.keys.alternative_cut_copy_paste = true
+editor.keys.alternative_cut_copy_paste.macos = false
+
+# true if shift-backspace sends the delete character,
+# false if shift-backspace just means backspace
+editor.keys.shift_backspace_is_delete = false
+
+# home and end keys should only travel to the start/end of the current line
+editor.keys.home_and_end_travel_far = false
+# home and end keys move to the first/last non-whitespace character,
+# and move to the actual start/end when pressed a second time.
+# Only works if editor.keys.home_and_end_travel_far is false.
+editor.keys.home_and_end_travel_smart = true
+# The OS X HI Guidelines say that home/end are relative to the document,
+# but that drives some people nuts. This pref enables/disables it.
+editor.keys.home_and_end_travel_far.macos = true
+
+# Enable/disable support for complex scripts. Used for Japanese and others,
+# but disable when not needed, otherwise basic Western European chars break.
+editor.input_method_support = false
+
+# convert tabs to spaces? how many spaces?
+editor.tabs.expand = true
+editor.tabs.size = 2
+
+# Set to true to automatically close [ { ( " and '
+editor.completion.auto_close = false
+
+# automatically indent each line
+editor.indent = true
+
+# Whether to check files to see if they've been modified externally
+editor.watcher = true
+# Set true to enable debugging, since this is quirky on others' machines
+editor.watcher.debug = false
+# The window of time (in milliseconds) in which a change won't be counted
+editor.watcher.window = 1500
+
+# Format and search engine to use for online queries
+search.format = https://google.com/search?q=%s
+
+# font choice and size for the console
+console.font.size = 12
+
+# number of lines to show by default
+console.lines = 4
+
+# Number of blank lines to advance/clear console.
+# Note that those lines are also printed in the terminal when
+# Processing is executed there.
+# Setting to 0 stops this behavior.
+console.head_padding = 10
+
+# Set to false to disable automatically clearing the console
+# each time 'run' is hit
+# If one sets it to false, one may also want to set 'console.head_padding'
+# to a positive number to separate outputs from different runs.
+console.auto_clear = true
+
+# number of days of history to keep around before cleaning
+# setting to 0 will never clean files
+console.temp.days = 7
+
+# set the maximum number of lines remembered by the console
+# the default is 500, lengthen at your own peril
+console.scrollback.lines = 500
+console.scrollback.chars = 40000
+
+# Any additional Java options when running.
+# If you change this and can't run things, it's your own durn fault.
+run.options =
+
+# settings for the -XmsNNNm and -XmxNNNm command line option
+run.options.memory = false
+run.options.memory.initial = 64
+run.options.memory.maximum = 512
+
+# Index of the display to use for running sketches (starts at 1).
+# Kept this 1-indexed because older vesions of Processing were setting
+# the preference even before it was being used.
+# -1 means the default display, 0 means all displays
+run.display = -1
+
+# set internally because it comes from the system
+#run.window.bgcolor=
+
+# set to false to open a new untitled window when closing the last window
+# (otherwise, the environment will quit)
+# default to the relative norm for the different platforms,
+# but the setting can be changed in the prefs dialog anyway
+#sketchbook.closing_last_window_quits = true
+#sketchbook.closing_last_window_quits.macos = false
+
+editor.untitled.prefix=sketch_
+# The old (pre-1.0, back for 2.0) style for default sketch name.
+# If you change this, be careful that this will work with your language
+# settings. For instance, MMMdd won't work on Korean-language systems
+# because it'll insert non-ASCII characters and break the environment.
+# https://github.com/processing/processing/issues/322
+editor.untitled.suffix=yyMMdd
+
+# replace underscores in .pde file names with spaces
+sketch.name.replace_underscore = true
+
+# what to use for generating sketch names (change in the prefs window)
+#sketch.name.approach =
+
+# number of days of build history and other temp files to keep around
+# these are kept around for debugging purposes, and in case code is lost
+temp.days = 7
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# whether or not to export as full screen (present) mode
+export.application.fullscreen = false
+
+# whether to show the stop button when exporting to application
+export.application.stop = true
+
+# embed Java by default for lower likelihood of problems
+export.application.embed_java = true
+
+# set to false to no longer delete application folders before export
+# (removed from the Preferences windows in 4.0 beta 9)
+export.delete_target_folder = true
+
+# may be useful when attempting to debug the preprocessor
+preproc.save_build_files=false
+
+# allows various preprocessor features to be toggled
+# in case they are causing problems
+
+# preprocessor: pde.g
+preproc.color_datatype = true
+preproc.web_colors = true
+preproc.enhanced_casting = true
+
+# preprocessor: PdeEmitter.java
+preproc.substitute_floats = true
+
+# PdePreproc.java
+# writes out the parse tree as parseTree.xml, which can be usefully
+# viewed in (at least) Mozilla or IE. useful when debugging the preprocessor.
+preproc.output_parse_tree = false
+
+# set to the program to be used for opening HTML files, folders, etc.
+#launcher.linux = xdg-open
+
+# FULL SCREEN (PRESENT MODE)
+run.present.bgcolor = #666666
+run.present.stop.color = #cccccc
+
+# PROXIES
+# Set a proxy server for folks that require it. This will allow the update
+# checker and the contrib manager to run properly in those environments.
+# This changed from proxy.host and proxy.port to proxy.http.host and
+# proxy.http.port in 3.0a8. In addition, https and socks were added.
+proxy.http.host=
+proxy.http.port=
+proxy.https.host=
+proxy.https.port=
+proxy.socks.host=
+proxy.socks.port=
+# Example of usage (replace 'http' with 'https' or 'socks' as needed)
+#proxy.http.host=proxy.example.com
+#proxy.http.port=8080
+# Whether to use the system proxy by default
+proxy.system=true
+
+# PDE X
+pdex.errorCheckEnabled = true
+pdex.warningsEnabled = true
+pdex.writeErrorLogs = false
+
+pdex.autoSave.autoSaveEnabled = false
+pdex.autoSaveInterval = 5
+pdex.autoSave.promptDisplay = true
+pdex.autoSave.autoSaveByDefault = true
+
+# Enable auto-completion when hitting ctrl-space
+pdex.completion = false
+# Setting this true will show completions whenever available, not just after ctrl-space
+pdex.completion.trigger = false
+# Suggest libraries to import when a class is undefined/unavailable
+pdex.suggest.imports = true
+# Set to false to disable ctrl/cmd-click jump to definition
+pdex.inspectMode.hotkey = true
From 108f0bb99f8039278a61fdcb3649d843395ecf69 Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Thu, 6 Feb 2025 23:31:53 +0100
Subject: [PATCH 010/160] Welcome to Beta screen: Msg fix
---
build/shared/lib/languages/PDE.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build/shared/lib/languages/PDE.properties b/build/shared/lib/languages/PDE.properties
index be680c159..74fd5027e 100644
--- a/build/shared/lib/languages/PDE.properties
+++ b/build/shared/lib/languages/PDE.properties
@@ -618,7 +618,7 @@ update_check.updates_available.contributions = There are updates available for s
# Beta
beta.window.title = Welcome to Beta
beta.title = Welcome to the Processing Beta
-beta.message = Thank you for trying out the new version of Processing. We?re very grateful!\n\nPlease report any bugs on the forums.
+beta.message = Thank you for trying out the new version of Processing. We're very grateful!\n\nPlease report any bugs on the forums.
beta.button = Got it!
# ---------------------------------------
From bebf792699542ef3cd610363b35bb4b3c43d5193 Mon Sep 17 00:00:00 2001
From: rishab
Date: Thu, 6 Mar 2025 20:51:44 +0530
Subject: [PATCH 011/160] pre multiplied projection matrix
---
core/src/processing/opengl/PGraphicsOpenGL.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java
index 88164f43e..2d6dca991 100644
--- a/core/src/processing/opengl/PGraphicsOpenGL.java
+++ b/core/src/processing/opengl/PGraphicsOpenGL.java
@@ -4481,7 +4481,7 @@ public class PGraphicsOpenGL extends PGraphics {
// The minus sign is needed to invert the Y axis.
projection.set(x, 0, 0, tx,
- 0, -y, 0, ty,
+ 0, -y, 0, -ty,
0, 0, z, tz,
0, 0, 0, 1);
From 34cc4387e4aa6fa6dba99bdeccf589ffb5f8a334 Mon Sep 17 00:00:00 2001
From: Yehia Rasheed <157399068+yehiarasheed@users.noreply.github.com>
Date: Fri, 7 Mar 2025 15:09:35 +0200
Subject: [PATCH 012/160] feat: Add handleMoveLines method with keystroke
support and ActionListeners
- Implement handleMoveLines to manage line movement functionality
- Add keystroke bindings for triggering line movements
- Integrate ActionListeners for responsive UI interactions
- Ensure cross-platform compatibility for macOS and Linux
---
app/src/processing/app/ui/Editor.java | 90 +++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java
index f87ba4ee1..5d54fd17b 100644
--- a/app/src/processing/app/ui/Editor.java
+++ b/app/src/processing/app/ui/Editor.java
@@ -821,6 +821,17 @@ public abstract class Editor extends JFrame implements RunnerListener {
editMenuUpdatable.add(action);
menu.add(item);
+ item = new JMenuItem("Move Selected Lines Up");
+ item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK));
+ item.addActionListener(e -> handleMoveLines(true));
+ menu.add(item);
+
+ item = new JMenuItem("Move Selected Lines Down");
+ item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK));
+ item.addActionListener(e -> handleMoveLines(false));
+ menu.add(item);
+
+
// Update copy/cut state on selection/de-selection
menu.addMenuListener(new MenuListener() {
// UndoAction and RedoAction do this for themselves.
@@ -1865,6 +1876,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
}
+
public void handleIndent() {
handleIndentOutdent(true);
}
@@ -1918,6 +1930,84 @@ public abstract class Editor extends JFrame implements RunnerListener {
stopCompoundEdit();
sketch.setModified(true);
}
+ /**
+ * Moves the selected lines up or down in the text editor.
+ *
+ *
If {@code moveUp} is true, the selected lines are moved up. If false, they move down.
+ *
This method ensures proper selection updates and handles edge cases like moving
+ * the first or last line.
+ *
+ * @param moveUp {@code true} to move the selection up, {@code false} to move it down.
+ */
+ public void handleMoveLines(boolean moveUp) {
+ startCompoundEdit();
+
+ int startLine = textarea.getSelectionStartLine();
+ int stopLine = textarea.getSelectionStopLine();
+
+ // Adjust selection if the last line isn't fully selected
+ if (startLine != stopLine &&
+ textarea.getSelectionStop() == textarea.getLineStartOffset(stopLine)) {
+ stopLine--;
+ }
+
+ int replacedLine = moveUp ? startLine - 1 : stopLine + 1;
+ if (replacedLine < 0 || replacedLine >= textarea.getLineCount()) {
+ stopCompoundEdit();
+ return;
+ }
+
+ final String source = textarea.getText(); // Get full text from textarea
+
+ int replaceStart = textarea.getLineStartOffset(replacedLine);
+ int replaceEnd = textarea.getLineStopOffset(replacedLine);
+ if (replaceEnd > source.length()) {
+ replaceEnd = source.length();
+ }
+
+ int selectionStart = textarea.getLineStartOffset(startLine);
+ int selectionEnd = textarea.getLineStopOffset(stopLine);
+ if (selectionEnd > source.length()) {
+ selectionEnd = source.length();
+ }
+
+ String replacedText = source.substring(replaceStart, replaceEnd);
+ String selectedText = source.substring(selectionStart, selectionEnd);
+
+ if (replacedLine == textarea.getLineCount() - 1) {
+ replacedText += "\n";
+ selectedText = selectedText.substring(0, Math.max(0, selectedText.length() - 1));
+ } else if (stopLine == textarea.getLineCount() - 1) {
+ selectedText += "\n";
+ replacedText = replacedText.substring(0, Math.max(0, replacedText.length() - 1));
+ }
+
+ int newSelectionStart, newSelectionEnd;
+ if (moveUp) {
+ textarea.select(selectionStart, selectionEnd);
+ textarea.setSelectedText(replacedText); // Use setSelectedText()
+
+ textarea.select(replaceStart, replaceEnd);
+ textarea.setSelectedText(selectedText);
+
+ newSelectionStart = textarea.getLineStartOffset(startLine - 1);
+ newSelectionEnd = textarea.getLineStopOffset(stopLine - 1);
+ } else {
+ textarea.select(replaceStart, replaceEnd);
+ textarea.setSelectedText(selectedText);
+
+ textarea.select(selectionStart, selectionEnd);
+ textarea.setSelectedText(replacedText);
+
+ newSelectionStart = textarea.getLineStartOffset(startLine + 1);
+ newSelectionEnd = stopLine + 1 < textarea.getLineCount()
+ ? Math.min(textarea.getLineStopOffset(stopLine + 1), source.length())
+ : textarea.getLineStopOffset(stopLine); // Prevent out-of-bounds
+ }
+
+ textarea.select(newSelectionStart, newSelectionEnd);
+ stopCompoundEdit();
+ }
static public boolean checkParen(char[] array, int index, int stop) {
From 938109dbbd786d784b7515d542cab9f0001b4279 Mon Sep 17 00:00:00 2001
From: yehiarasheed
Date: Fri, 7 Mar 2025 16:43:22 +0200
Subject: [PATCH 013/160] Fix selection bug in handleMoveLines on macOS by
using invokeLater()
Previously, moving lines down on macOS caused incorrect selection, moving
the cursor to the end of the enclosing braces instead of properly selecting the moved line. This issue did not occur on Windows.
The fix ensures that selection updates happen inside Swing's event
dispatch thread by wrapping the selection logic in SwingUtilities.invokeLater().
This guarantees proper selection behavior across all platforms.
Additionally, updated the JavaDoc for the method to reflect the fix and clarify
the behavior of the selection update.
Tested on Windows and macOS.
---
app/src/processing/app/ui/Editor.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java
index 5d54fd17b..9736787d2 100644
--- a/app/src/processing/app/ui/Editor.java
+++ b/app/src/processing/app/ui/Editor.java
@@ -1936,6 +1936,8 @@ public abstract class Editor extends JFrame implements RunnerListener {
*
If {@code moveUp} is true, the selected lines are moved up. If false, they move down.
*
This method ensures proper selection updates and handles edge cases like moving
* the first or last line.
+ *
This operation is undo/redoable, allowing the user to revert the action using
+ * {@code Ctrl/Cmd + Z} (Undo) and redo with {@code Ctrl/Cmd + Y} (Redo).
*
* @param moveUp {@code true} to move the selection up, {@code false} to move it down.
*/
@@ -2005,7 +2007,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
: textarea.getLineStopOffset(stopLine); // Prevent out-of-bounds
}
- textarea.select(newSelectionStart, newSelectionEnd);
+ SwingUtilities.invokeLater(() -> textarea.select(newSelectionStart, newSelectionEnd));
stopCompoundEdit();
}
From 77b354d403e76194e783a04a3b82072c82349834 Mon Sep 17 00:00:00 2001
From: yehiarasheed
Date: Fri, 7 Mar 2025 17:23:56 +0200
Subject: [PATCH 014/160] Update JavaDoc to clarify redo keybinding on macOS
Updated the JavaDoc to reflect that the redo command on macOS is {@code Shift + Cmd + Z},
not {@code Cmd + Y}, and may vary on other platforms. This ensures the documentation is
accurate and aligns with the actual keybindings.
No functional code changes were made.
---
app/src/processing/app/ui/Editor.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/src/processing/app/ui/Editor.java b/app/src/processing/app/ui/Editor.java
index 9736787d2..3817c4294 100644
--- a/app/src/processing/app/ui/Editor.java
+++ b/app/src/processing/app/ui/Editor.java
@@ -1937,7 +1937,8 @@ public abstract class Editor extends JFrame implements RunnerListener {
*
This method ensures proper selection updates and handles edge cases like moving
* the first or last line.
*
This operation is undo/redoable, allowing the user to revert the action using
- * {@code Ctrl/Cmd + Z} (Undo) and redo with {@code Ctrl/Cmd + Y} (Redo).
+ * {@code Ctrl/Cmd + Z} (Undo). Redo functionality is available through the
+ * keybinding {@code Ctrl/Cmd + Z} on Windows/Linux and {@code Shift + Cmd + Z} on macOS.
*
* @param moveUp {@code true} to move the selection up, {@code false} to move it down.
*/
From 801b02b52b46c238772394b3765329587301965d Mon Sep 17 00:00:00 2001
From: rishab
Date: Sat, 8 Mar 2025 20:40:09 +0530
Subject: [PATCH 015/160] added keyEvent tests
---
core/src/processing/core/PApplet.java | 1 +
.../processing/core/PAppletKeyEventTest.java | 142 ++++++++++++++++++
2 files changed, 143 insertions(+)
create mode 100644 core/test/processing/core/PAppletKeyEventTest.java
diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java
index 24c0d5d39..d96784a3f 100644
--- a/core/src/processing/core/PApplet.java
+++ b/core/src/processing/core/PApplet.java
@@ -2842,6 +2842,7 @@ public class PApplet implements PConstants {
public void focusLost() {
// TODO: if user overrides this without calling super it's not gonna work
pressedKeys.clear();
+ keyPressed = false;
}
diff --git a/core/test/processing/core/PAppletKeyEventTest.java b/core/test/processing/core/PAppletKeyEventTest.java
new file mode 100644
index 000000000..361010d3f
--- /dev/null
+++ b/core/test/processing/core/PAppletKeyEventTest.java
@@ -0,0 +1,142 @@
+package processing.core;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import processing.event.KeyEvent;
+import java.util.HashSet;
+import java.util.Iterator;
+
+public class PAppletKeyEventTest {
+
+ private static final int SHIFT_MASK = 1;
+ private static final int CTRL_MASK = 2;
+ private static final int ALT_MASK = 4;
+
+ private PApplet applet;
+
+ @Before
+ public void setup() {
+ applet = new PApplet();
+ }
+
+ @Test
+ public void testSingleKeyPressAndRelease() {
+ KeyEvent pressEvent = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'a', 65, false);
+ applet.handleKeyEvent(pressEvent);
+ Assert.assertEquals(1, applet.pressedKeys.size());
+
+ KeyEvent releaseEvent = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, 'a', 65, false);
+ applet.handleKeyEvent(releaseEvent);
+ Assert.assertEquals(0, applet.pressedKeys.size());
+ Assert.assertFalse(applet.keyPressed);
+ }
+
+ @Test
+ public void testShiftAndLetterSequence() {
+ KeyEvent pressA = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'a', 65, false);
+ applet.handleKeyEvent(pressA);
+
+ KeyEvent pressShift = new KeyEvent(null, 0L, KeyEvent.PRESS, SHIFT_MASK, 'A', 16, false);
+ applet.handleKeyEvent(pressShift);
+
+ KeyEvent releaseA = new KeyEvent(null, 0L, KeyEvent.RELEASE, SHIFT_MASK, 'A', 65, false);
+ applet.handleKeyEvent(releaseA);
+
+ KeyEvent releaseShift = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, 'A', 16, false);
+ applet.handleKeyEvent(releaseShift);
+
+ Assert.assertFalse("keyPressed should be false after all keys released", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should be empty", true, applet.pressedKeys.isEmpty());
+ }
+
+ @Test
+ public void testControlAndLetterSequence() {
+ KeyEvent pressCtrl = new KeyEvent(null, 0L, KeyEvent.PRESS, CTRL_MASK, '\0', 17, false);
+ applet.handleKeyEvent(pressCtrl);
+
+ KeyEvent pressC = new KeyEvent(null, 0L, KeyEvent.PRESS, CTRL_MASK, (char)3, 67, false);
+ applet.handleKeyEvent(pressC);
+
+ KeyEvent releaseC = new KeyEvent(null, 0L, KeyEvent.RELEASE, CTRL_MASK, 'c', 67, false);
+ applet.handleKeyEvent(releaseC);
+
+ KeyEvent releaseCtrl = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, '\0', 17, false);
+ applet.handleKeyEvent(releaseCtrl);
+
+ Assert.assertFalse("keyPressed should be false after all keys released", applet.keyPressed);
+ Assert.assertTrue("pressedKeys should be empty", applet.pressedKeys.isEmpty());
+ }
+
+ @Test
+ public void testAltAndLetterSequence() {
+ KeyEvent pressV = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'v', 86, false);
+ applet.handleKeyEvent(pressV);
+
+ KeyEvent pressAlt = new KeyEvent(null, 0L, KeyEvent.PRESS, ALT_MASK, 'v', 18, false);
+ applet.handleKeyEvent(pressAlt);
+
+ KeyEvent releaseV = new KeyEvent(null, 0L, KeyEvent.RELEASE, ALT_MASK, 'v', 86, false);
+ applet.handleKeyEvent(releaseV);
+
+ KeyEvent releaseAlt = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, 'v', 18, false);
+ applet.handleKeyEvent(releaseAlt);
+
+ Assert.assertFalse("keyPressed should be false after all keys released", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should be empty", true, applet.pressedKeys.isEmpty());
+ }
+
+ @Test
+ public void testKeyRepeat() {
+ applet.keyRepeatEnabled = false;
+
+ KeyEvent pressR = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'r', 82, false);
+ applet.handleKeyEvent(pressR);
+
+ KeyEvent repeatR = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'r', 82, true);
+ applet.handleKeyEvent(repeatR);
+
+ Assert.assertTrue("keyPressed should be true after key press", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should have 1 entry", 1, applet.pressedKeys.size());
+
+ KeyEvent releaseR = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, 'r', 82, false);
+ applet.handleKeyEvent(releaseR);
+
+ Assert.assertFalse("keyPressed should be false after key release", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should be empty", true, applet.pressedKeys.isEmpty());
+ }
+
+ @Test
+ public void testKeyRepeatEnabled() {
+ applet.keyRepeatEnabled = true;
+
+ KeyEvent pressT = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 't', 84, false);
+ applet.handleKeyEvent(pressT);
+
+ KeyEvent repeatT = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 't', 84, true);
+ applet.handleKeyEvent(repeatT);
+
+ Assert.assertTrue("keyPressed should be true with key repeat enabled", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should have 1 entry", 1, applet.pressedKeys.size());
+
+ KeyEvent releaseT = new KeyEvent(null, 0L, KeyEvent.RELEASE, 0, 't', 84, false);
+ applet.handleKeyEvent(releaseT);
+
+ Assert.assertFalse("keyPressed should be false after key release", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should be empty", true, applet.pressedKeys.isEmpty());
+ }
+
+ @Test
+ public void testKeyFocusLost() {
+ KeyEvent pressF = new KeyEvent(null, 0L, KeyEvent.PRESS, 0, 'f', 70, false);
+ applet.handleKeyEvent(pressF);
+
+ Assert.assertTrue("keyPressed should be true after key press", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should have 1 entry", 1, applet.pressedKeys.size());
+
+ applet.focusLost();
+
+ Assert.assertFalse("keyPressed should be false after focus lost", applet.keyPressed);
+ Assert.assertEquals("pressedKeys should be empty after focus lost", true, applet.pressedKeys.isEmpty());
+ }
+}
From be9e6b8fac98ee6ad7cd120228fb30f1e4840087 Mon Sep 17 00:00:00 2001
From: rishab
Date: Sat, 8 Mar 2025 21:08:33 +0530
Subject: [PATCH 016/160] minor changes
---
core/test/processing/core/PAppletKeyEventTest.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/core/test/processing/core/PAppletKeyEventTest.java b/core/test/processing/core/PAppletKeyEventTest.java
index 361010d3f..f40511ec5 100644
--- a/core/test/processing/core/PAppletKeyEventTest.java
+++ b/core/test/processing/core/PAppletKeyEventTest.java
@@ -4,8 +4,6 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import processing.event.KeyEvent;
-import java.util.HashSet;
-import java.util.Iterator;
public class PAppletKeyEventTest {
From 30dddff7608558155c6427934dd279c5636275ac Mon Sep 17 00:00:00 2001
From: Stef Tervelde
Date: Sun, 9 Mar 2025 19:12:45 +0100
Subject: [PATCH 017/160] macOS distribution
---
app/build.gradle.kts | 59 +++++++++++++++++++++++++----
app/macos/background.png | Bin 0 -> 14866 bytes
app/{ => macos}/entitlements.plist | 0
app/{ => macos}/info.plist | 0
4 files changed, 52 insertions(+), 7 deletions(-)
create mode 100644 app/macos/background.png
rename app/{ => macos}/entitlements.plist (100%)
rename app/{ => macos}/info.plist (100%)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e7ef2e5b3..0e01f30d1 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,8 @@
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
+import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
+import org.jetbrains.kotlin.fir.scopes.impl.overrides
plugins{
id("java")
@@ -51,23 +53,24 @@ compose.desktop {
packageName = "Processing"
macOS{
- bundleID = "org.processing.app"
- iconFile = project.file("../build/macos/processing.icns")
+ bundleID = "${rootProject.group}.app"
+ iconFile = rootProject.file("build/macos/processing.icns")
infoPlist{
- extraKeysRawXml = layout.projectDirectory.file("info.plist").asFile.readText()
+ extraKeysRawXml = file("macos/info.plist").readText()
}
- entitlementsFile.set(project.file("entitlements.plist"))
- runtimeEntitlementsFile.set(project.file("entitlements.plist"))
+ entitlementsFile.set(file("macos/entitlements.plist"))
+ runtimeEntitlementsFile.set(file("macos/entitlements.plist"))
+ appStore = true
}
windows{
- iconFile = project.file("../build/windows/processing.ico")
+ iconFile = rootProject.file("build/windows/processing.ico")
menuGroup = "Processing"
upgradeUuid = "89d8d7fe-5602-4b12-ba10-0fe78efbd602"
}
linux {
appCategory = "Programming"
menuGroup = "Processing"
- iconFile = project.file("../build/linux/processing.png")
+ iconFile = rootProject.file("build/linux/processing.png")
// Fix fonts on some Linux distributions
jvmArgs("-Dawt.useSystemAAFontSettings=on")
@@ -105,6 +108,48 @@ tasks.compileJava{
options.encoding = "UTF-8"
}
+tasks.register("installCreateDmg") {
+ commandLine("brew", "install", "--quiet", "create-dmg")
+}
+tasks.register("packageCustomDmg"){
+ group = "compose desktop"
+
+ val distributable = tasks.named("createDistributable").get()
+ dependsOn(distributable, "installCreateDmg")
+
+ val packageName = distributable.packageName.get()
+ val dir = distributable.destinationDir.get()
+ val dmg = dir.file("../dmg/$packageName-$version.dmg").asFile
+ val app = dir.file("$packageName.app").asFile
+
+ dmg.parentFile.deleteRecursively()
+ dmg.parentFile.mkdirs()
+
+ commandLine("brew", "install", "--quiet", "create-dmg")
+
+ commandLine("create-dmg",
+ "--volname", packageName,
+ "--volicon", rootProject.file("build/macos/processing.icns"),
+ "--background", file("macos/background.png"),
+ "--icon", "$packageName.app", "200", "200",
+ "--window-pos", "200", "200",
+ "--window-size", "775", "485",
+ "--app-drop-link", "500", "200",
+ "--hide-extension", "$packageName.app",
+ dmg,
+ app
+ )
+}
+
+afterEvaluate{
+ tasks.named("packageDmg").configure{
+ dependsOn("packageCustomDmg")
+ group = "compose desktop"
+ actions = emptyList()
+ }
+}
+
+
// LEGACY TASKS
// Most of these are shims to be compatible with the old build system
diff --git a/app/macos/background.png b/app/macos/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..765619b73dccc7ef89a8cd602a2573d9e89d9c95
GIT binary patch
literal 14866
zcmeHOc|4W*_kS?CQfQ_ujdi9;kz!Q3B1;=hMd4OT(SkNhF?DUZC7DVzqs^41D3vVH
zq!cbjB12LmW66?`JxiAGJD+E}&-HEQ_xt_#{bQcjtK9o6pU>wx=X}n2pZ7WUDOAOmsK5^}sN>ndqO$Dy#3h;G~F$mDy4(
zu~?}EzI@?qy4DoK?uJhKw0#1G>Bp^FZfe67X{+8Bs+3oeU)Mk5s}M=?#;$pBont?*
zvq*YsdRKYEPPG??dxM{)N>p+lSbmSsC?0-
zQR_1khYxH!J(B(IfT82;EU5`&9a62np&PvBbY>`VXdZi}hC(ecy!
zm+=)3T=Kg+FtK^Z<-@rj3*NLU%~7%pI{1DlW?6dkp{nM!`c;{m2DqEEzxkNgl906|
zR-@9rago#5q0V+~qfdkP{kl?JZr8a?GW_9NnW|*f_XQi1?EU+@^#X%DrYHU;W$*vU
zMLW}H(A(Iuy(xaR?M$URQ}mKDq%2E{IicE~i3eTNkJWO!>dl&N%go~@e*MnWEvqae
z({rI^RMwG^ff$$9nlkT{EHC!_arkfvr&FdzEOAPVU66fEYO2SpxQHgry4pgEW&XY%
z!(Q(%s}^(Mk4s7X@c>2kZg#Wv{vu3b+gSmix`jCDlD*Z6mKl!vOwY-Yc<%!%?(
zS-bQ2!14g&*KO?&rb??TTZhD*T&mienVwx8lRY!wrDPpnqI=lOyY8vR(ygXl-S>P_
zB9;XE)INNlU8$zjtIrP(FsQ3l$$u#+E{6Y&{!+TOu*eYIg#9v+-Lvl@QFZsM=Qn-=+l7$$;C(R{n|
z74D%g>4gT1Q47_W?99SMK{)6znStKZL~^xkUg~LjmO3C1=!R-RK}Q6!Jh>qfxl{jKe}T`x9~Z(YdWjD?ORL}>|y0Y
zYgli}8cAH74(ANOC(VAwCN9Fgi^;{?g_mle;Y@Vvu*9O~a}#bFgU;$th+q<6O2G%`
zgP0rzFDfML6R84Wvkh>QQgEE6fMKZ*{`>-$UrewlvS^3xq^81_k|M^McZuqfx*?Ph
zth;DBh7}$(z-Ya$mK9ld)E(0)j6fzuN>MG)R1>!abc(rSu$2*d7P5U!j!*RO9r>@2qNU`wIeEXq&hL0o&HJ?yG?v0kqlo@aX<$M{>@GR8T#QswkXLA;_sm)+@
z=>VV*(yj!K0KNEh7Ijl}80Dor!bF%V7ZM}}1{NG3@SYe$<ee%VNS)2%q;EAcAE
zU3Pu7F3I=SM2Tr}dN2BC9vK<7cgfY_csj=U__f^b?|GTpq;2m%RQjxkqrF;oYpF=c
zbr1iM^49XKVaGTA4czpUfVp#1qvDE7IKxSc?%I?}DYbFE8{M3nZoe7*{o&rg>yECy
zb5%Q{SIferW4<{_&nfnbPC6rp~!Sn%bzvFn4+}^sR(=2HL5HK
zU8!4e_XbyEbs%OFwuiobK3;jT!0&o30bus4FBVE!&%AZkA2p+`f#|IEAk0G^jD5h#
z$O`Tl7o!FjECA1UmuEx-sYWM=BDRyQPCCouu?}v3UO-1_wZOO+)a#INNN(W-kZbv`
zlwVtk#~X~FBY=+B%J9qJ!yLnTlL;q!7*d;}`pxqr4=ks5?u$csBqls45nESI-vKC-
z5$y5T7Cb`v6bp4csA~xLAyvs@gS8_}hjyx&lDa4A>TaO8mz)l2!
zLufbsnXDn|PLw)MD2nXKn1FYR@R{F@rTkzJ3j@|3+Ujg>@n
z^j*Kq^$zuTm3P1HiQ9>WmV=pt9UZNu4e!6LtmAqozjfgbJ??z7rSX%eLflp3%!l%C
zMw#=iul6_v;{noXOtK$J_q%BF(ZKxHOUfdAfWCx2-)bFxdfgXGFXt+=I
zg67bXu>P>Frl|d8n>IUL%U0drf2e9AD=b7Kzijzc8E^aQ+K$rNUrhG~x;yL%XR;}k
z#%0k$bc)rA!#UYYLT<^bd~ls^yfjMec)-Y*zjm>!yIIH_3Nj%+McH!Wp?g5B*c%5|
zMs3WPYd(>+$o*bJ3#(I-W#<3XC)aJzoh8L8DK6&tEMOZaZeT~E{tKyaPt!xpNU-boFmhPnboRAzj41w!7w}V0sou0zU#kRM}+(RhE)R_D?@Ji=B$c?X*xR6{)Yq2PdLJ&Mm-Uua)
z^pfyokl>P>zNeuoTqi?nk?RB^fKw2Hf;n^+gXgEb6dEG*LcpErVC919aJp=DD6^+H~7)6Us6NfApYz%;^4mX`huc~-PT#E(pEk#UiL
zDje2~W+x>_X4zDZ4|hSpUqFpU$3>KVjic4zRz&X5LZX2V;-yeVj1w1hmi-6!FKH4-
zF^76y5Icn+DTHvE!?|x(k^qq))%deXHiF^