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/build.gradle.kts b/app/build.gradle.kts
index 2bd30a09d..8c62f07bf 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
@@ -29,6 +31,9 @@ sourceSets{
kotlin{
srcDirs("src")
}
+ resources{
+ srcDirs("resources", listOf("languages", "fonts", "theme").map { "../build/shared/lib/$it" })
+ }
}
test{
kotlin{
@@ -104,6 +109,8 @@ dependencies {
implementation(libs.compottie)
implementation(libs.kaml)
+ implementation(libs.markdown)
+ implementation(libs.markdownJVM)
testImplementation(kotlin("test"))
testImplementation(libs.mockitoKotlin)
diff --git a/app/src/main/resources/bird.svg b/app/src/main/resources/bird.svg
new file mode 100644
index 000000000..90d69c899
--- /dev/null
+++ b/app/src/main/resources/bird.svg
@@ -0,0 +1,5 @@
+
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
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/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)
-
- val preferences by remember {
- mutableStateOf(Properties())
- }
-
- LaunchedEffect(watched){
- val defaults = Base::class.java.getResourceAsStream("/lib/${DEFAULTS_FILE_NAME}") ?: return@LaunchedEffect
+ watchFile(preferencesFile)
- preferences.load(defaults)
- preferences.load(preferencesFile.inputStream())
+ return Properties().apply {
+ load(ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME) ?: InputStream.nullInputStream())
+ 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/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java
index 40ffe24c0..1bfa29688 100644
--- a/app/src/processing/app/UpdateCheck.java
+++ b/app/src/processing/app/UpdateCheck.java
@@ -31,6 +31,7 @@
import javax.swing.JOptionPane;
+import processing.app.ui.WelcomeToBeta;
import processing.core.PApplet;
@@ -116,7 +117,7 @@ public void updateCheck() throws IOException {
long now = System.currentTimeMillis();
if (lastString != null) {
long when = Long.parseLong(lastString);
- if (now - when < ONE_DAY) {
+ if (now - when < ONE_DAY && !Base.DEBUG) {
// don't annoy the shit outta people
return;
}
@@ -134,6 +135,9 @@ public void updateCheck() throws IOException {
// offerToUpdateContributions = !promptToVisitDownloadPage();
promptToVisitDownloadPage();
}
+ if(latest < Base.getRevision()){
+ WelcomeToBeta.showWelcomeToBeta();
+ }
/*
if (offerToUpdateContributions) {
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
new file mode 100644
index 000000000..d7492fa6a
--- /dev/null
+++ b/app/src/processing/app/ui/WelcomeToBeta.kt
@@ -0,0 +1,211 @@
+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.MaterialTheme
+import androidx.compose.material.MaterialTheme.colors
+import androidx.compose.material.MaterialTheme.typography
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+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
+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 com.formdev.flatlaf.util.SystemInfo
+import com.mikepenz.markdown.compose.Markdown
+import com.mikepenz.markdown.m2.markdownColor
+import com.mikepenz.markdown.m2.markdownTypography
+import com.mikepenz.markdown.model.MarkdownColors
+import com.mikepenz.markdown.model.MarkdownTypography
+import processing.app.Base.getRevision
+import processing.app.Base.getVersionName
+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
+
+
+class WelcomeToBeta {
+ companion object{
+ val windowSize = Dimension(400, 200)
+ val windowTitle = Locale()["beta.window.title"]
+
+ @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 {
+ size = windowSize
+ setContent {
+ ProcessingTheme {
+ 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(close: () -> Unit = {}) {
+ Row(
+ modifier = Modifier
+ .padding(20.dp, 10.dp)
+ .size(windowSize.width.dp, windowSize.height.dp),
+ horizontalArrangement = Arrangement
+ .spacedBy(20.dp)
+ ){
+ val locale = LocalLocale.current
+ Image(
+ painter = painterResource("bird.svg"),
+ contentDescription = locale["beta.logo"],
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .size(100.dp, 100.dp)
+ .offset(0.dp, (-25).dp)
+ )
+ Column(
+ modifier = Modifier
+ .fillMaxHeight(),
+ verticalArrangement = Arrangement
+ .spacedBy(
+ 10.dp,
+ alignment = Alignment.CenterVertically
+ )
+ ) {
+ Text(
+ text = locale["beta.title"],
+ style = typography.subtitle1,
+ )
+ val text = locale["beta.message"]
+ .replace('$' + "version", getVersionName())
+ .replace('$' + "revision", getRevision().toString())
+ Markdown(
+ text,
+ colors = markdownColor(),
+ typography = markdownTypography(text = typography.body1, link = typography.body1.copy(color = colors.primary)),
+ modifier = Modifier.background(Color.Transparent).padding(bottom = 10.dp)
+ )
+ Row {
+ Spacer(modifier = Modifier.weight(1f))
+ PDEButton(onClick = {
+ close()
+ }) {
+ Text(
+ text = locale["beta.button"],
+ color = colors.onPrimary
+ )
+ }
+ }
+ }
+ }
+ }
+ @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) colors.primaryVariant else colors.primary)
+
+ Box(modifier = Modifier.padding(end = 5.dp, top = 5.dp)) {
+ Box(
+ modifier = Modifier
+ .offset((-offset).dp, (offset).dp)
+ .background(theme.getColor("toolbar.button.pressed.field"))
+ .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) {
+ application {
+ val windowState = rememberWindowState(
+ size = DpSize.Unspecified,
+ position = WindowPosition(Alignment.Center)
+ )
+
+ Window(onCloseRequest = ::exitApplication, state = windowState, title = windowTitle) {
+ 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..254c0946c
--- /dev/null
+++ b/app/src/processing/app/ui/theme/Locale.kt
@@ -0,0 +1,45 @@
+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.Messages
+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(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)"))
+ 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, key)
+}
+val LocalLocale = compositionLocalOf { Locale() }
+@Composable
+fun LocaleProvider(content: @Composable () -> Unit) {
+ 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()
+ }
+}
\ 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..735d8e5b2
--- /dev/null
+++ b/app/src/processing/app/ui/theme/Theme.kt
@@ -0,0 +1,75 @@
+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 processing.app.LocalPreferences
+import processing.app.PreferencesProvider
+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
+) {
+ 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")
+ )
+
+ 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..30446ecd1 100644
--- a/build/shared/lib/languages/PDE.properties
+++ b/build/shared/lib/languages/PDE.properties
@@ -613,7 +613,6 @@ update_check = Update
update_check.updates_available.core = A new version of Processing is available,\nwould you like to visit the Processing download page?
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?
-
# ---------------------------------------
# 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
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ccc3a55e6..a9fe0b6e5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,6 +25,8 @@ netbeansSwing = { module = "org.netbeans.api:org-netbeans-swing-outline", versio
ant = { module = "org.apache.ant:ant", version = "1.10.14" }
lsp4j = { module = "org.eclipse.lsp4j:org.eclipse.lsp4j", version = "0.22.0" }
jsoup = { module = "org.jsoup:jsoup", version = "1.17.2" }
+markdown = { module = "com.mikepenz:multiplatform-markdown-renderer-m2", version = "0.31.0" }
+markdownJVM = { module = "com.mikepenz:multiplatform-markdown-renderer-jvm", version = "0.31.0" }
[plugins]
jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }