mirror of
https://github.com/processing/processing4.git
synced 2026-05-09 12:22:43 +02:00
Merge branch 'main' into gradle-plugin
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
name: Pre-releases with Gradle
|
||||
name: Branch Builds
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
@@ -6,31 +6,58 @@ on:
|
||||
- '.all-contributorsrc'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test Processing
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew test
|
||||
build:
|
||||
name: Create Pre-release for ${{ matrix.os_prefix }} (${{ matrix.arch }})
|
||||
name: (${{ matrix.os_prefix }}/${{ matrix.arch }}) Create Processing Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
contents: write
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: [self-hosted, linux, ARM64]
|
||||
- os: ubuntu-24.04-arm
|
||||
os_prefix: linux
|
||||
arch: aarch64
|
||||
binary: processing*.snap
|
||||
- os: ubuntu-latest
|
||||
os_prefix: linux
|
||||
arch: x64
|
||||
binary: processing*.snap
|
||||
- os: windows-latest
|
||||
os_prefix: windows
|
||||
arch: x64
|
||||
binary: msi/Processing-*.msi
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: x64
|
||||
binary: dmg/Processing-*.dmg
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: aarch64
|
||||
binary: dmg/Processing-*.dmg
|
||||
steps:
|
||||
- name: Install Snapcraft
|
||||
if: runner.os == 'Linux'
|
||||
uses: samuelmeuli/action-snapcraft@v3
|
||||
- name: Install LXD
|
||||
if: runner.os == 'Linux'
|
||||
uses: canonical/setup-lxd@main
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Java
|
||||
@@ -41,19 +68,13 @@ jobs:
|
||||
architecture: ${{ matrix.arch }}
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew packageDistributionForCurrentOS
|
||||
- name: Add instructions
|
||||
if: ${{ matrix.os_prefix == 'macos' }}
|
||||
run: |
|
||||
echo "run 'xattr -d com.apple.quarantine Processing-${version}.dmg' to remove the quarantine flag" > ./app/build/compose/binaries/main/dmg/INSTRUCTIONS_FOR_TESTING.txt
|
||||
|
||||
- name: Add artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: processing-${{ github.ref_name }}-${{github.sha}}-${{ matrix.os_prefix }}-${{ matrix.arch }}-gradle
|
||||
path: |
|
||||
./app/build/compose/binaries/main/dmg/Processing-*.dmg
|
||||
./app/build/compose/binaries/main/dmg/INSTRUCTIONS_FOR_TESTING.txt
|
||||
./app/build/compose/binaries/main/msi/Processing-*.msi
|
||||
./app/build/compose/binaries/main/deb/processing*.deb
|
||||
name: processing-${{ matrix.os_prefix }}-${{ matrix.arch }}-br_${{ github.ref_name }}
|
||||
retention-days: 1
|
||||
path: app/build/compose/binaries/main/${{ matrix.binary }}
|
||||
@@ -1,37 +0,0 @@
|
||||
name: Maven Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to release'
|
||||
required: true
|
||||
default: '1.0.0'
|
||||
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Create Processing Core Release on Maven Central
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew publish
|
||||
env:
|
||||
MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
|
||||
MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
|
||||
|
||||
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
|
||||
|
||||
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY_KEY }}
|
||||
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_IN_MEMORY_KEY_PASSWORD }}
|
||||
|
||||
ORG_GRADLE_PROJECT_version: ${{ github.event.inputs.version }}
|
||||
@@ -7,12 +7,26 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Pull Request Build for ${{ matrix.os_prefix }} (${{ matrix.arch }})
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test Processing
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew test
|
||||
build:
|
||||
name: (${{ matrix.os_prefix }}/${{ matrix.arch }}) Create Processing Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -20,19 +34,31 @@ jobs:
|
||||
- os: ubuntu-24.04-arm
|
||||
os_prefix: linux
|
||||
arch: aarch64
|
||||
binary: processing*.snap
|
||||
- os: ubuntu-latest
|
||||
os_prefix: linux
|
||||
arch: x64
|
||||
binary: processing*.snap
|
||||
- os: windows-latest
|
||||
os_prefix: windows
|
||||
arch: x64
|
||||
binary: msi/Processing-*.msi
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: x64
|
||||
binary: dmg/Processing-*.dmg
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: aarch64
|
||||
binary: dmg/Processing-*.dmg
|
||||
steps:
|
||||
- name: Install Snapcraft
|
||||
if: runner.os == 'Linux'
|
||||
uses: samuelmeuli/action-snapcraft@v3
|
||||
- name: Install LXD
|
||||
if: runner.os == 'Linux'
|
||||
uses: canonical/setup-lxd@main
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Java
|
||||
@@ -43,19 +69,13 @@ jobs:
|
||||
architecture: ${{ matrix.arch }}
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew packageDistributionForCurrentOS
|
||||
- name: Add instructions
|
||||
if: ${{ matrix.os_prefix == 'macos' }}
|
||||
run: |
|
||||
echo "run 'xattr -d com.apple.quarantine Processing-${version}.dmg' to remove the quarantine flag" > ./app/build/compose/binaries/main/dmg/INSTRUCTIONS_FOR_TESTING.txt
|
||||
|
||||
- name: Add artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: processing-pr${{ github.event.pull_request.number }}-${{github.sha}}-${{ matrix.os_prefix }}-${{ matrix.arch }}-gradle
|
||||
path: |
|
||||
./app/build/compose/binaries/main/dmg/Processing-*.dmg
|
||||
./app/build/compose/binaries/main/dmg/INSTRUCTIONS_FOR_TESTING.txt
|
||||
./app/build/compose/binaries/main/msi/Processing-*.msi
|
||||
./app/build/compose/binaries/main/deb/processing*.deb
|
||||
name: processing-${{ matrix.os_prefix }}-${{ matrix.arch }}-pr_${{ github.event.pull_request.number }}
|
||||
retention-days: 5
|
||||
path: app/build/compose/binaries/main/${{ matrix.binary }}
|
||||
@@ -7,22 +7,50 @@ jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
build_number: ${{ steps.tag_info.outputs.build_number }}
|
||||
revision: ${{ steps.tag_info.outputs.revision }}
|
||||
version: ${{ steps.tag_info.outputs.version }}
|
||||
steps:
|
||||
- name: Extract version and build number
|
||||
- name: Extract version and revision
|
||||
id: tag_info
|
||||
shell: bash
|
||||
run: |
|
||||
TAG_NAME="${GITHUB_REF#refs/tags/}"
|
||||
BUILD_NUMBER=$(echo "$TAG_NAME" | cut -d'-' -f2)
|
||||
REVISION=$(echo "$TAG_NAME" | cut -d'-' -f2)
|
||||
VERSION=$(echo "$TAG_NAME" | cut -d'-' -f3)
|
||||
|
||||
# Set outputs for use in later jobs or steps
|
||||
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "revision=$REVISION" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
reference:
|
||||
name: Publish Processing Reference to release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
needs: version
|
||||
steps:
|
||||
- name: Checkout Website Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: processing/processing-website
|
||||
- name: Use Node.js 16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Make reference.zip
|
||||
run: npm run zip
|
||||
- name: Upload reference to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
asset_name: processing-${{ needs.version.outputs.version }}-reference.zip
|
||||
file: reference.zip
|
||||
|
||||
publish:
|
||||
name: Publish Processing Core to Maven Central
|
||||
name: Publish Processing Libraries to Maven Central
|
||||
runs-on: ubuntu-latest
|
||||
needs: version
|
||||
steps:
|
||||
@@ -35,6 +63,7 @@ jobs:
|
||||
java-version: 17
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew publish
|
||||
env:
|
||||
@@ -48,9 +77,9 @@ jobs:
|
||||
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_IN_MEMORY_KEY_PASSWORD }}
|
||||
|
||||
ORG_GRADLE_PROJECT_version: ${{ needs.version.outputs.version }}
|
||||
ORG_GRADLE_PROJECT_group: ${{ vars.PROCESSING_GROUP }}
|
||||
ORG_GRADLE_PROJECT_group: ${{ vars.GRADLE_GROUP }}
|
||||
build:
|
||||
name: Publish Release for ${{ matrix.os_prefix }} (${{ matrix.arch }})
|
||||
name: (${{ matrix.os_prefix }}/${{ matrix.arch }}) Create Processing Release
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: version
|
||||
permissions:
|
||||
@@ -59,26 +88,47 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# compiling for arm32 needs a self-hosted runner on Raspi OS (32-bit)
|
||||
- os: [self-hosted, linux, ARM]
|
||||
- os: ubuntu-24.04-arm
|
||||
os_prefix: linux
|
||||
arch: arm
|
||||
arch: aarch64
|
||||
binary: ${{ vars.SNAP_NAME }}_${{ needs.version.outputs.version }}_arm64
|
||||
extension: snap
|
||||
- os: ubuntu-latest
|
||||
os_prefix: linux
|
||||
arch: x64
|
||||
binary: ${{ vars.SNAP_NAME }}_${{ needs.version.outputs.version }}_amd64
|
||||
extension: snap
|
||||
- os: windows-latest
|
||||
os_prefix: windows
|
||||
arch: x64
|
||||
binary: msi/Processing-${{ needs.version.outputs.version }}
|
||||
extension: msi
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: x64
|
||||
binary: dmg/Processing-${{ needs.version.outputs.version }}
|
||||
extension: dmg
|
||||
- os: macos-latest
|
||||
os_prefix: macos
|
||||
arch: aarch64
|
||||
- os: macos-latest
|
||||
os_prefix: linux
|
||||
arch: aarch64
|
||||
binary: dmg/Processing-${{ needs.version.outputs.version }}
|
||||
extension: dmg
|
||||
steps:
|
||||
- name: Install Certificates for Code Signing
|
||||
if: runner.os == 'macOS'
|
||||
continue-on-error: true
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
|
||||
- name: Install Snapcraft
|
||||
if: runner.os == 'Linux'
|
||||
uses: samuelmeuli/action-snapcraft@v3
|
||||
- name: Install LXD
|
||||
if: runner.os == 'Linux'
|
||||
uses: canonical/setup-lxd@main
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Java
|
||||
@@ -89,25 +139,53 @@ jobs:
|
||||
architecture: ${{ matrix.arch }}
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
# - name: Install Certificates for Code Signing
|
||||
# if: ${{ matrix.os_prefix == 'macos' }}
|
||||
# uses: apple-actions/import-codesign-certs@v3
|
||||
# with:
|
||||
# p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
# p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew packageDistributionForCurrentOS
|
||||
env:
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_version: ${{ needs.version.outputs.version }}
|
||||
ORG_GRADLE_PROJECT_group: ${{ vars.PROCESSING_GROUP }}
|
||||
ORG_GRADLE_PROJECT_group: ${{ vars.GRADLE_GROUP }}
|
||||
ORG_GRADLE_PROJECT_revision: ${{ needs.version.outputs.revision }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.verbose: true
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.sign: ${{ secrets.PROCESSING_SIGNING }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.signing.identity: ${{ secrets.PROCESSING_SIGNING_IDENTITY }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.appleID: ${{ secrets.PROCESSING_APPLE_ID }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.password: ${{ secrets.PROCESSING_APP_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_compose.desktop.mac.notarization.teamID: ${{ secrets.PROCESSING_TEAM_ID }}
|
||||
ORG_GRADLE_PROJECT_snapname: ${{ vars.SNAP_NAME }}
|
||||
|
||||
- name: Upload binaries to release
|
||||
- name: Upload portables to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: |
|
||||
./app/build/compose/binaries/main/dmg/Processing-*.dmg
|
||||
./app/build/compose/binaries/main/dmg/INSTRUCTIONS_FOR_TESTING.txt
|
||||
./app/build/compose/binaries/main/msi/Processing-*.msi
|
||||
./app/build/compose/binaries/main/deb/processing*.deb
|
||||
file_glob: true
|
||||
asset_name: processing-${{ needs.version.outputs.version }}-${{ matrix.os_prefix }}-${{ matrix.arch }}-portable.zip
|
||||
file: app/build/compose/binaries/main/Processing-${{ needs.version.outputs.version }}.zip
|
||||
|
||||
- name: Upload installers to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
asset_name: processing-${{ needs.version.outputs.version }}-${{ matrix.os_prefix }}-${{ matrix.arch }}.${{ matrix.extension }}
|
||||
file: app/build/compose/binaries/main/${{ matrix.binary }}.${{ matrix.extension }}
|
||||
|
||||
- name: Upload snap to Snap Store
|
||||
if: runner.os == 'Linux'
|
||||
run: snapcraft upload --release=beta app/build/compose/binaries/main/${{ matrix.binary }}.${{ matrix.extension }}
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.PROCESSING_SNAPCRAFT_TOKEN }}
|
||||
|
||||
- name: Sign files with Trusted Signing
|
||||
if: runner.os == 'Windows'
|
||||
uses: azure/trusted-signing-action@v0
|
||||
with:
|
||||
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||
endpoint: https://eus.codesigning.azure.net/
|
||||
trusted-signing-account-name: vscx-codesigning
|
||||
certificate-profile-name: vscx-certificate-profile
|
||||
files-folder: app/build/compose/binaries/main/msi
|
||||
files-folder-filter: msi
|
||||
file-digest: SHA256
|
||||
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
||||
timestamp-digest: SHA256
|
||||
@@ -113,3 +113,6 @@ java/build/
|
||||
/core/examples/build
|
||||
/java/gradle/build
|
||||
/java/gradle/example/.processing
|
||||
|
||||
.build/
|
||||
/app/windows/obj
|
||||
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M400 500C700 500 700 100 400 100" stroke="#0468FF" stroke-width="150"/>
|
||||
<path d="M400 200L100 600" stroke="#1F34AB" stroke-width="150"/>
|
||||
<path d="M100 300L200 500" stroke="#85AEFF" stroke-width="150"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 324 B |
Generated
-1
@@ -4,7 +4,6 @@
|
||||
<option name="env">
|
||||
<map>
|
||||
<entry key="DEBUG" value="true" />
|
||||
<entry key="ORG_GRADLE_PROJECT_version" value="Development Build" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="executionName" />
|
||||
|
||||
@@ -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(){
|
||||
|
||||
}
|
||||
}
|
||||
+303
-16
@@ -1,6 +1,14 @@
|
||||
import org.gradle.kotlin.dsl.support.zipTo
|
||||
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
|
||||
import java.io.FileOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
// TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload
|
||||
|
||||
plugins{
|
||||
id("java")
|
||||
@@ -12,9 +20,6 @@ plugins{
|
||||
alias(libs.plugins.download)
|
||||
}
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
repositories{
|
||||
mavenCentral()
|
||||
google()
|
||||
@@ -29,6 +34,14 @@ sourceSets{
|
||||
kotlin{
|
||||
srcDirs("src")
|
||||
}
|
||||
resources{
|
||||
srcDirs("resources", listOf("languages", "fonts", "theme").map { "../build/shared/lib/$it" })
|
||||
}
|
||||
}
|
||||
test{
|
||||
kotlin{
|
||||
srcDirs("test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,37 +50,38 @@ compose.desktop {
|
||||
mainClass = "processing.app.ui.Start"
|
||||
|
||||
jvmArgs(*listOf(
|
||||
Pair("processing.version", version),
|
||||
Pair("processing.revision", "1300"),
|
||||
Pair("processing.contributions.source", "https://contributions-preview.processing.org/contribs.txt"),
|
||||
Pair("processing.version", rootProject.version),
|
||||
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
|
||||
Pair("processing.contributions.source", "https://download.processing.org/contribs.txt"),
|
||||
Pair("processing.download.page", "https://processing.org/download/"),
|
||||
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
|
||||
Pair("processing.tutorials", "https://processing.org/tutorials/"),
|
||||
).map { "-D${it.first}=${it.second}" }.toTypedArray())
|
||||
|
||||
nativeDistributions{
|
||||
modules("jdk.jdi", "java.compiler", "jdk.accessibility")
|
||||
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "java.management.rmi")
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||
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")
|
||||
menuGroup = "Development;Programming;"
|
||||
iconFile = rootProject.file("build/linux/processing.png")
|
||||
// Fix fonts on some Linux distributions
|
||||
jvmArgs("-Dawt.useSystemAAFontSettings=on")
|
||||
|
||||
@@ -99,12 +113,191 @@ dependencies {
|
||||
|
||||
implementation(libs.compottie)
|
||||
implementation(libs.kaml)
|
||||
implementation(libs.markdown)
|
||||
implementation(libs.markdownJVM)
|
||||
|
||||
testImplementation(kotlin("test"))
|
||||
testImplementation(libs.mockitoKotlin)
|
||||
testImplementation(libs.junitJupiter)
|
||||
testImplementation(libs.junitJupiterParams)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
workingDir = file("build/test")
|
||||
workingDir.mkdirs()
|
||||
}
|
||||
|
||||
tasks.compileJava{
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
val version = if(project.version == "unspecified") "1.0.0" else project.version
|
||||
|
||||
tasks.register<Exec>("installCreateDmg") {
|
||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
|
||||
commandLine("arch", "-arm64", "brew", "install", "--quiet", "create-dmg")
|
||||
}
|
||||
tasks.register<Exec>("packageCustomDmg"){
|
||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
|
||||
group = "compose desktop"
|
||||
|
||||
val distributable = tasks.named<AbstractJPackageTask>("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()
|
||||
|
||||
val extra = mutableListOf<String>()
|
||||
val isSigned = compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
|
||||
|
||||
if(!isSigned) {
|
||||
val content = """
|
||||
run 'xattr -d com.apple.quarantine Processing-${version}.dmg' to remove the quarantine flag
|
||||
""".trimIndent()
|
||||
val instructions = dmg.parentFile.resolve("INSTRUCTIONS.txt")
|
||||
instructions.writeText(content)
|
||||
extra.add("--add-file")
|
||||
extra.add("INSTRUCTIONS.txt")
|
||||
extra.add(instructions.path)
|
||||
extra.add("200")
|
||||
extra.add("25")
|
||||
}
|
||||
|
||||
commandLine("brew", "install", "--quiet", "create-dmg")
|
||||
|
||||
commandLine("create-dmg",
|
||||
"--volname", packageName,
|
||||
"--volicon", file("macos/volume.icns"),
|
||||
"--background", file("macos/background.png"),
|
||||
"--icon", "$packageName.app", "190", "185",
|
||||
"--window-pos", "200", "200",
|
||||
"--window-size", "658", "422",
|
||||
"--app-drop-link", "466", "185",
|
||||
"--hide-extension", "$packageName.app",
|
||||
*extra.toTypedArray(),
|
||||
dmg,
|
||||
app
|
||||
)
|
||||
}
|
||||
|
||||
tasks.register<Exec>("packageCustomMsi"){
|
||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isWindows }
|
||||
dependsOn("createDistributable")
|
||||
workingDir = file("windows")
|
||||
group = "compose desktop"
|
||||
|
||||
val version = if(version == "unspecified") "1.0.0" else version
|
||||
|
||||
commandLine(
|
||||
"dotnet",
|
||||
"build",
|
||||
"/p:Platform=x64",
|
||||
"/p:Version=$version",
|
||||
"/p:DefineConstants=\"Version=$version;\""
|
||||
)
|
||||
}
|
||||
|
||||
val snapname = findProperty("snapname") ?: rootProject.name
|
||||
val snaparch = when (System.getProperty("os.arch")) {
|
||||
"amd64", "x86_64" -> "amd64"
|
||||
"aarch64" -> "arm64"
|
||||
else -> System.getProperty("os.arch")
|
||||
}
|
||||
tasks.register("generateSnapConfiguration"){
|
||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isLinux }
|
||||
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
||||
dependsOn(distributable)
|
||||
|
||||
val dir = distributable.destinationDir.get()
|
||||
val content = """
|
||||
name: $snapname
|
||||
version: $version
|
||||
base: core22
|
||||
summary: A creative coding editor
|
||||
description: |
|
||||
Processing is a flexible software sketchbook and a programming language designed for learning how to code.
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
processing:
|
||||
command: opt/processing/bin/Processing
|
||||
desktop: opt/processing/lib/processing-Processing.desktop
|
||||
environment:
|
||||
LD_LIBRARY_PATH: ${'$'}SNAP/opt/processing/lib/runtime/lib:${'$'}LD_LIBRARY_PATH
|
||||
LIBGL_DRIVERS_PATH: ${'$'}SNAP/usr/lib/${'$'}SNAPCRAFT_ARCH_TRIPLET/dri
|
||||
plugs:
|
||||
- desktop
|
||||
- desktop-legacy
|
||||
- wayland
|
||||
- x11
|
||||
- network
|
||||
- opengl
|
||||
|
||||
parts:
|
||||
processing:
|
||||
plugin: dump
|
||||
source: deb/processing_$version-1_$snaparch.deb
|
||||
source-type: deb
|
||||
stage-packages:
|
||||
- openjdk-17-jre
|
||||
override-prime: |
|
||||
snapcraftctl prime
|
||||
chmod -R +x opt/processing/lib/app/resources/jdk-*
|
||||
rm -vf usr/lib/jvm/java-17-openjdk-*/lib/security/cacerts
|
||||
""".trimIndent()
|
||||
dir.file("../snapcraft.yaml").asFile.writeText(content)
|
||||
}
|
||||
|
||||
tasks.register<Exec>("packageSnap"){
|
||||
onlyIf { org.gradle.internal.os.OperatingSystem.current().isLinux }
|
||||
dependsOn("packageDeb", "generateSnapConfiguration")
|
||||
group = "compose desktop"
|
||||
|
||||
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
||||
workingDir = distributable.destinationDir.dir("../").get().asFile
|
||||
commandLine("snapcraft")
|
||||
}
|
||||
tasks.register<Zip>("zipDistributable"){
|
||||
dependsOn("createDistributable", "setExecutablePermissions")
|
||||
group = "compose desktop"
|
||||
|
||||
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
||||
val dir = distributable.destinationDir.get()
|
||||
val packageName = distributable.packageName.get()
|
||||
|
||||
from(dir){ eachFile{ permissions{ unix("755") } } }
|
||||
archiveBaseName.set(packageName)
|
||||
destinationDirectory.set(dir.file("../").asFile)
|
||||
}
|
||||
|
||||
afterEvaluate{
|
||||
tasks.named("packageDmg").configure{
|
||||
dependsOn("packageCustomDmg")
|
||||
group = "compose desktop"
|
||||
actions = emptyList()
|
||||
}
|
||||
|
||||
tasks.named("packageMsi").configure{
|
||||
dependsOn("packageCustomMsi")
|
||||
group = "compose desktop"
|
||||
actions = emptyList()
|
||||
}
|
||||
tasks.named("packageDistributionForCurrentOS").configure {
|
||||
if(org.gradle.internal.os.OperatingSystem.current().isMacOsX
|
||||
&& compose.desktop.application.nativeDistributions.macOS.notarization.appleID.isPresent
|
||||
){
|
||||
dependsOn("notarizeDmg")
|
||||
}
|
||||
dependsOn("packageSnap", "zipDistributable")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// LEGACY TASKS
|
||||
// Most of these are shims to be compatible with the old build system
|
||||
@@ -220,6 +413,97 @@ tasks.register<Copy>("renameWindres") {
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
into(dir)
|
||||
}
|
||||
tasks.register("signResources"){
|
||||
onlyIf {
|
||||
org.gradle.internal.os.OperatingSystem.current().isMacOsX
|
||||
&&
|
||||
compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
|
||||
}
|
||||
group = "compose desktop"
|
||||
dependsOn(
|
||||
"includeCore",
|
||||
"includeJavaMode",
|
||||
"includeJdk",
|
||||
"includeSharedAssets",
|
||||
"includeProcessingExamples",
|
||||
"includeProcessingWebsiteExamples",
|
||||
"includeJavaModeResources",
|
||||
"renameWindres"
|
||||
)
|
||||
finalizedBy("prepareAppResources")
|
||||
|
||||
val resourcesPath = composeResources("")
|
||||
|
||||
|
||||
|
||||
// find jars in the resources directory
|
||||
val jars = mutableListOf<File>()
|
||||
doFirst{
|
||||
fileTree(resourcesPath)
|
||||
.matching { include("**/Info.plist") }
|
||||
.singleOrNull()
|
||||
?.let { file ->
|
||||
copy {
|
||||
from(file)
|
||||
into(resourcesPath)
|
||||
}
|
||||
}
|
||||
fileTree(resourcesPath) {
|
||||
include("**/*.jar")
|
||||
exclude("**/*.jar.tmp/**")
|
||||
}.forEach { file ->
|
||||
val tempDir = file.parentFile.resolve("${file.name}.tmp")
|
||||
copy {
|
||||
from(zipTree(file))
|
||||
into(tempDir)
|
||||
}
|
||||
file.delete()
|
||||
jars.add(tempDir)
|
||||
}
|
||||
fileTree(resourcesPath){
|
||||
include("**/bin/**")
|
||||
include("**/*.jnilib")
|
||||
include("**/*.dylib")
|
||||
include("**/*aarch64*")
|
||||
include("**/*x86_64*")
|
||||
include("**/*ffmpeg*")
|
||||
include("**/ffmpeg*/**")
|
||||
exclude("jdk-*/**")
|
||||
exclude("*.jar")
|
||||
exclude("*.so")
|
||||
exclude("*.dll")
|
||||
}.forEach{ file ->
|
||||
exec {
|
||||
commandLine("codesign", "--timestamp", "--force", "--deep","--options=runtime", "--sign", "Developer ID Application", file)
|
||||
}
|
||||
}
|
||||
jars.forEach { file ->
|
||||
FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos ->
|
||||
ZipOutputStream(fos).use { zos ->
|
||||
file.walkTopDown().forEach { fileEntry ->
|
||||
if (fileEntry.isFile) {
|
||||
// Calculate the relative path for the zip entry
|
||||
val zipEntryPath = fileEntry.relativeTo(file).path
|
||||
val entry = ZipEntry(zipEntryPath)
|
||||
zos.putNextEntry(entry)
|
||||
|
||||
// Copy file contents to the zip
|
||||
fileEntry.inputStream().use { input ->
|
||||
input.copyTo(zos)
|
||||
}
|
||||
zos.closeEntry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.deleteRecursively()
|
||||
}
|
||||
file(composeResources("Info.plist")).delete()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
afterEvaluate {
|
||||
tasks.named("prepareAppResources").configure {
|
||||
@@ -253,5 +537,8 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.findByName("createDistributable")?.finalizedBy("setExecutablePermissions")
|
||||
tasks.named("createDistributable").configure {
|
||||
dependsOn("signResources")
|
||||
finalizedBy("setExecutablePermissions")
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 497 KiB |
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
<svg width="900" height="900" viewBox="0 0 900 900" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M456.735 552.393L155.9 151.279" stroke="#A44D28" stroke-width="150.418"/>
|
||||
<path d="M757.575 452.113C456.738 552.391 456.738 752.948 155.903 652.67" stroke="#FF7D45" stroke-width="150.418"/>
|
||||
<path d="M556.832 552.392L456.555 51" stroke="#FFBEA2" stroke-width="150.418"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 386 B |
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M400 500C700 500 700 100 400 100" stroke="#0468FF" stroke-width="150"/>
|
||||
<path d="M400 200L100 600" stroke="#1F34AB" stroke-width="150"/>
|
||||
<path d="M100 300L200 500" stroke="#85AEFF" stroke-width="150"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 329 B |
@@ -124,6 +124,7 @@ public class Base {
|
||||
|
||||
|
||||
static public void main(final String[] args) {
|
||||
Messages.log("Starting Processing version" + VERSION_NAME + " revision "+ REVISION);
|
||||
EventQueue.invokeLater(() -> {
|
||||
try {
|
||||
createAndShowGUI(args);
|
||||
@@ -563,14 +564,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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1366,10 +1365,10 @@ public class Base {
|
||||
* @param schemeUri the full URI, including pde://
|
||||
*/
|
||||
public Editor handleScheme(String schemeUri) {
|
||||
// var result = Schema.handleSchema(schemeUri, this);
|
||||
// if (result != null) {
|
||||
// return result;
|
||||
// }
|
||||
var result = Schema.handleSchema(schemeUri, this);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String location = schemeUri.substring(6);
|
||||
if (location.length() > 0) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package processing.app;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -330,6 +329,7 @@ public class Library extends LocalContribution {
|
||||
* imports to specific libraries.
|
||||
* @param importToLibraryTable mapping from package names to Library objects
|
||||
*/
|
||||
static boolean instructed = false;
|
||||
// public void addPackageList(HashMap<String,Library> importToLibraryTable) {
|
||||
public void addPackageList(Map<String, List<Library>> importToLibraryTable) {
|
||||
// PApplet.println(packages);
|
||||
@@ -342,18 +342,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(!instructed) {
|
||||
instructed = 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);
|
||||
|
||||
@@ -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 <br/> clears to the next line
|
||||
// second <br/> is a shorter height blank space before the trace
|
||||
Toolkit.formatMessage("$message<br/><tt><br/>$sw</tt>"),
|
||||
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), //"<html><body>" +
|
||||
//"<b>" + primary + "</b>" +
|
||||
//"<br>" + 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"
|
||||
}
|
||||
@@ -577,18 +577,25 @@ public class Platform {
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
/**
|
||||
* These methods were refactored to use the Preferences system instead of
|
||||
* actual environment variables, since modifying environment variables at runtime
|
||||
* proved problematic. This approach provides similar functionality
|
||||
* while being compatible with various platforms and execution environments.
|
||||
*
|
||||
* This abstraction maintains a consistent API for environment-like variable storage
|
||||
* while implementing it differently under the hood to work around runtime limitations.
|
||||
*/
|
||||
|
||||
static public void setenv(String variable, String value) {
|
||||
inst.setenv(variable, value);
|
||||
Preferences.set(variable, value);
|
||||
}
|
||||
|
||||
|
||||
static public String getenv(String variable) {
|
||||
return inst.getenv(variable);
|
||||
return Preferences.get(variable);
|
||||
}
|
||||
|
||||
|
||||
static public int unsetenv(String variable) {
|
||||
return inst.unsetenv(variable);
|
||||
throw new RuntimeException("unsetenv() not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
+18
-16
@@ -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<Properties> { error("No preferences provided") }
|
||||
@Composable
|
||||
fun PreferencesProvider(content: @Composable () -> Unit){
|
||||
val preferences = loadPreferences()
|
||||
CompositionLocalProvider(LocalPreferences provides preferences){
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,11 @@ class Schema {
|
||||
private fun handleSketchUrl(uri: URI): Editor?{
|
||||
val url = File(uri.path.replace("/url/", ""))
|
||||
|
||||
val tempSketchFolder = File(Base.untitledFolder, url.nameWithoutExtension)
|
||||
val rand = (1..6)
|
||||
.map { (('a'..'z') + ('A'..'Z')).random() }
|
||||
.joinToString("")
|
||||
|
||||
val tempSketchFolder = File(File(Base.untitledFolder, rand), url.nameWithoutExtension)
|
||||
tempSketchFolder.mkdirs()
|
||||
val tempSketchFile = File(tempSketchFolder, "${tempSketchFolder.name}.pde")
|
||||
|
||||
@@ -71,7 +75,7 @@ class Schema {
|
||||
?.map { it.split("=") }
|
||||
?.associate {
|
||||
URLDecoder.decode(it[0], StandardCharsets.UTF_8) to
|
||||
URLDecoder.decode(it[1], StandardCharsets.UTF_8)
|
||||
URLDecoder.decode(it[1], StandardCharsets.UTF_8)
|
||||
}
|
||||
?: emptyMap()
|
||||
options["data"]?.let{ data ->
|
||||
@@ -81,7 +85,7 @@ class Schema {
|
||||
downloadFiles(uri, code, File(sketchFolder, "code"))
|
||||
}
|
||||
options["pde"]?.let{ pde ->
|
||||
downloadFiles(uri, pde, sketchFolder)
|
||||
downloadFiles(uri, pde, sketchFolder, "pde")
|
||||
}
|
||||
options["mode"]?.let{ mode ->
|
||||
val modeFile = File(sketchFolder, "sketch.properties")
|
||||
@@ -89,7 +93,7 @@ class Schema {
|
||||
}
|
||||
|
||||
}
|
||||
private fun downloadFiles(uri: URI, urlList: String, targetFolder: File){
|
||||
private fun downloadFiles(uri: URI, urlList: String, targetFolder: File, extension: String = ""){
|
||||
Thread{
|
||||
targetFolder.mkdirs()
|
||||
|
||||
@@ -101,37 +105,31 @@ class Schema {
|
||||
val files = urlList.split(",")
|
||||
|
||||
files.filter { it.isNotBlank() }
|
||||
.map{ it.split(":", limit = 2) }
|
||||
.map{ segments ->
|
||||
if(segments.size == 2){
|
||||
if(segments[0].isBlank()){
|
||||
return@map listOf(null, segments[1])
|
||||
}
|
||||
return@map segments
|
||||
}
|
||||
return@map listOf(null, segments[0])
|
||||
.map {
|
||||
if (it.contains(":")) it
|
||||
else "$it:$it"
|
||||
}
|
||||
.map{ it.split(":", limit = 2) }
|
||||
.forEach { (name, content) ->
|
||||
var target = File(targetFolder, name)
|
||||
if(extension.isNotBlank() && target.extension != extension){
|
||||
target = File(targetFolder, "$name.$extension")
|
||||
}
|
||||
try{
|
||||
// Try to decode the content as base64
|
||||
val file = Base64.getDecoder().decode(content)
|
||||
if(name == null){
|
||||
if(name.isBlank()){
|
||||
Messages.err("Base64 files needs to start with a file name followed by a colon")
|
||||
return@forEach
|
||||
}
|
||||
File(targetFolder, name).writeBytes(file)
|
||||
target.writeBytes(file)
|
||||
}catch(_: IllegalArgumentException){
|
||||
// Assume it's a URL and download it
|
||||
var url = URI.create(content)
|
||||
if(url.host == null){
|
||||
url = URI.create("https://$base/$content")
|
||||
}
|
||||
if(url.scheme == null){
|
||||
url = URI.create("https://$content")
|
||||
}
|
||||
|
||||
val target = File(targetFolder, name ?: url.path.split("/").last())
|
||||
url.toURL().openStream().use { input ->
|
||||
val url = URL(when{
|
||||
content.startsWith("https://") -> content
|
||||
content.startsWith("http://") -> content.replace("http://", "https://")
|
||||
URL("https://$content").path.isNotBlank() -> "https://$content"
|
||||
else -> "https://$base/$content"
|
||||
})
|
||||
url.openStream().use { input ->
|
||||
target.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
@@ -148,7 +146,7 @@ class Schema {
|
||||
?.map { it.split("=") }
|
||||
?.associate {
|
||||
URLDecoder.decode(it[0], StandardCharsets.UTF_8) to
|
||||
URLDecoder.decode(it[1], StandardCharsets.UTF_8)
|
||||
URLDecoder.decode(it[1], StandardCharsets.UTF_8)
|
||||
}
|
||||
?: emptyMap()
|
||||
for ((key, value) in options){
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Random;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import processing.app.ui.WelcomeToBeta;
|
||||
import processing.core.PApplet;
|
||||
|
||||
|
||||
@@ -116,7 +117,7 @@ public class UpdateCheck {
|
||||
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 class UpdateCheck {
|
||||
// offerToUpdateContributions = !promptToVisitDownloadPage();
|
||||
promptToVisitDownloadPage();
|
||||
}
|
||||
if(latest < Base.getRevision()){
|
||||
WelcomeToBeta.showWelcomeToBeta();
|
||||
}
|
||||
|
||||
/*
|
||||
if (offerToUpdateContributions) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Messages;
|
||||
import processing.app.UpdateCheck;
|
||||
import processing.app.Util;
|
||||
import processing.core.PApplet;
|
||||
@@ -228,6 +229,7 @@ public class ContributionListing {
|
||||
public void downloadAvailableList(final Base base,
|
||||
final ContribProgress progress) {
|
||||
// TODO: replace with SwingWorker [jv]
|
||||
Messages.log("Downloading contributions list from " + LISTING_URL);
|
||||
new Thread(() -> {
|
||||
downloadingLock.lock();
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -257,31 +257,31 @@ public class DefaultPlatform {
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
public interface CLibrary extends Library {
|
||||
CLibrary INSTANCE = Native.load("c", CLibrary.class);
|
||||
int setenv(String name, String value, int overwrite);
|
||||
String getenv(String name);
|
||||
int unsetenv(String name);
|
||||
int putenv(String string);
|
||||
}
|
||||
|
||||
|
||||
public void setenv(String variable, String value) {
|
||||
CLibrary clib = CLibrary.INSTANCE;
|
||||
clib.setenv(variable, value, 1);
|
||||
}
|
||||
|
||||
|
||||
public String getenv(String variable) {
|
||||
CLibrary clib = CLibrary.INSTANCE;
|
||||
return clib.getenv(variable);
|
||||
}
|
||||
|
||||
|
||||
public int unsetenv(String variable) {
|
||||
CLibrary clib = CLibrary.INSTANCE;
|
||||
return clib.unsetenv(variable);
|
||||
}
|
||||
// public interface CLibrary extends Library {
|
||||
// CLibrary INSTANCE = Native.load("c", CLibrary.class);
|
||||
// int setenv(String name, String value, int overwrite);
|
||||
// String getenv(String name);
|
||||
// int unsetenv(String name);
|
||||
// int putenv(String string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public void setenv(String variable, String value) {
|
||||
// CLibrary clib = CLibrary.INSTANCE;
|
||||
// clib.setenv(variable, value, 1);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public String getenv(String variable) {
|
||||
// CLibrary clib = CLibrary.INSTANCE;
|
||||
// return clib.getenv(variable);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public int unsetenv(String variable) {
|
||||
// CLibrary clib = CLibrary.INSTANCE;
|
||||
// return clib.unsetenv(variable);
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
@@ -33,7 +33,8 @@ import processing.core.PApplet;
|
||||
|
||||
|
||||
public class LinuxPlatform extends DefaultPlatform {
|
||||
String homeDir;
|
||||
// Switched to use ~ as the home directory for compatibility with snap
|
||||
String homeDir = "~";
|
||||
|
||||
|
||||
public void initBase(Base base) {
|
||||
@@ -98,7 +99,7 @@ public class LinuxPlatform extends DefaultPlatform {
|
||||
File configHome = null;
|
||||
|
||||
// Check to see if the user has set a different location for their config
|
||||
String configHomeEnv = getenv("XDG_CONFIG_HOME");
|
||||
String configHomeEnv = System.getenv("XDG_CONFIG_HOME");
|
||||
if (configHomeEnv != null && !configHomeEnv.isBlank()) {
|
||||
configHome = new File(configHomeEnv);
|
||||
if (!configHome.exists()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String>) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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<Theme> { 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")
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,113 @@
|
||||
package processing.app
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.Mockito.mockStatic
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import java.io.File
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
class SchemaTest {
|
||||
private val base: Base = mock<Base>{
|
||||
|
||||
}
|
||||
companion object {
|
||||
val preferences: MockedStatic<Preferences> = mockStatic(Preferences::class.java)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testLocalFiles() {
|
||||
val file = "/this/is/a/local/file"
|
||||
Schema.handleSchema("pde://$file", base)
|
||||
verify(base).handleOpen(file)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNewSketch() {
|
||||
Schema.handleSchema("pde://sketch/new", base)
|
||||
verify(base).handleNew()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
@Test
|
||||
fun testBase64SketchAndExtraFiles() {
|
||||
val sketch = """
|
||||
void setup(){
|
||||
|
||||
}
|
||||
void draw(){
|
||||
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val base64 = Base64.encode(sketch.toByteArray())
|
||||
Schema.handleSchema("pde://sketch/base64/$base64?pde=AnotherFile:$base64", base)
|
||||
val captor = ArgumentCaptor.forClass(String::class.java)
|
||||
|
||||
verify(base).handleOpenUntitled(captor.capture())
|
||||
|
||||
val file = File(captor.value)
|
||||
assert(file.exists())
|
||||
assert(file.readText() == sketch)
|
||||
|
||||
val extra = file.parentFile.resolve("AnotherFile.pde")
|
||||
assert(extra.exists())
|
||||
assert(extra.readText() == sketch)
|
||||
file.parentFile.deleteRecursively()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testURLSketch() {
|
||||
Schema.handleSchema("pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/Array/Array.pde", base)
|
||||
|
||||
val captor = ArgumentCaptor.forClass(String::class.java)
|
||||
verify(base).handleOpenUntitled(captor.capture())
|
||||
val output = File(captor.value)
|
||||
assert(output.exists())
|
||||
assert(output.name == "Array.pde")
|
||||
assert(output.extension == "pde")
|
||||
assert(output.parentFile.name == "Array")
|
||||
|
||||
output.parentFile.parentFile.deleteRecursively()
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = [
|
||||
"Module.pde:https://github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/ArrayObjects/Module.pde",
|
||||
"Module.pde",
|
||||
"Module:Module.pde",
|
||||
"Module:https://github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/ArrayObjects/Module.pde",
|
||||
"Module.pde:github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/ArrayObjects/Module.pde"
|
||||
])
|
||||
fun testURLSketchWithFile(file: String){
|
||||
Schema.handleSchema("pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/ArrayObjects/ArrayObjects.pde?pde=$file", base)
|
||||
|
||||
val captor = ArgumentCaptor.forClass(String::class.java)
|
||||
verify(base).handleOpenUntitled(captor.capture())
|
||||
|
||||
// wait for threads to resolve
|
||||
Thread.sleep(1000)
|
||||
|
||||
val output = File(captor.value)
|
||||
assert(output.parentFile.name == "ArrayObjects")
|
||||
assert(output.exists())
|
||||
assert(output.parentFile.resolve("Module.pde").exists())
|
||||
output.parentFile.parentFile.deleteRecursively()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPreferences() {
|
||||
Schema.handleSchema("pde://preferences?test=value", base)
|
||||
preferences.verify {
|
||||
Preferences.set("test", "value")
|
||||
Preferences.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="WixToolset.Sdk/5.0.1">
|
||||
<PropertyGroup>
|
||||
<OutputPath>..\build\compose\binaries\main\msi</OutputPath>
|
||||
<OutputName>Processing-$(Version)</OutputName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WixToolset.UI.wixext" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,35 @@
|
||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
|
||||
<Package Name="Processing" Manufacturer="Processing Foundation" Version="$(Version)" UpgradeCode="89d8d7fe-5602-4b12-ba10-0fe78efbd602">
|
||||
<Icon Id="icon.ico" SourceFile="..\..\build\windows\processing.ico" />
|
||||
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
|
||||
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
||||
<ui:WixUI Id="WixUI_Mondo" InstallDirectory="INSTALLFOLDER" />
|
||||
|
||||
<WixVariable Id="WixUILicenseRtf" Value="LICENSE.rtf" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="background.png" />
|
||||
<WixVariable Id="WixUIBannerBmp" Value="banner.png" />
|
||||
<Feature Id="MainApplication" Title="Processing" Level="1">
|
||||
<Files Include="..\build\compose\binaries\main\app\Processing\**" />
|
||||
<ComponentRef Id="ApplicationShortcut" />
|
||||
</Feature>
|
||||
<Directory Id="ProgramMenuFolder">
|
||||
<Directory Id="ApplicationProgramsFolder" Name="Processing"/>
|
||||
</Directory>
|
||||
<Directory Id="ProgramFiles64Folder">
|
||||
<Directory Id="INSTALLFOLDER" Name="Processing">
|
||||
</Directory>
|
||||
</Directory>
|
||||
<Component Id="ApplicationShortcut" Guid="b15e6d69-f054-4ec2-aade-8e3756b537d6">
|
||||
<Shortcut Id="ApplicationStartMenuShortcut"
|
||||
Name="Processing"
|
||||
Description="My Application Description"
|
||||
Directory="ApplicationProgramsFolder"
|
||||
Target="[INSTALLFOLDER]\Processing.exe"
|
||||
WorkingDirectory="INSTALLFOLDER"/>
|
||||
<RemoveFolder Id="CleanUpShortCut" Directory="ApplicationProgramsFolder" On="uninstall"/>
|
||||
<RegistryValue Root="HKCU" Key="Software\Processing Foundation\Processing" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
|
||||
</Component>
|
||||
</Package>
|
||||
</Wix>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,6 +1,3 @@
|
||||
group = "org.processing"
|
||||
version = "4.4.0"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version libs.versions.kotlin apply false
|
||||
alias(libs.plugins.kotlinMultiplatform) apply false
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ dependencies {
|
||||
```
|
||||
|
||||
## Developing for Core
|
||||
The easiest way to develop for core, without the need to build the whole project, is to use the `examples/src` sketches. In
|
||||
The easiest way to develop for core, without the need to build the whole project, is to use the `examples/src` sketches.
|
||||
|
||||
## PGraphics Modes
|
||||
Documentation on how to develop graphics modes as a library should go here.
|
||||
|
||||
@@ -6,8 +6,6 @@ plugins {
|
||||
alias(libs.plugins.mavenPublish)
|
||||
}
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = uri("https://jogamp.org/deployment/maven") }
|
||||
@@ -23,6 +21,11 @@ sourceSets{
|
||||
exclude("**/*.java")
|
||||
}
|
||||
}
|
||||
test{
|
||||
java{
|
||||
srcDirs("test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -70,4 +73,7 @@ tasks.test {
|
||||
}
|
||||
tasks.withType<Jar> {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
}
|
||||
tasks.compileJava{
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
@@ -3,17 +3,21 @@ kotlin = "2.0.20"
|
||||
compose-plugin = "1.7.1"
|
||||
jogl = "2.5.0"
|
||||
antlr = "4.13.2"
|
||||
jupiter = "5.12.0"
|
||||
|
||||
[libraries]
|
||||
jogl = { module = "org.jogamp.jogl:jogl-all-main", version.ref = "jogl" }
|
||||
gluegen = { module = "org.jogamp.gluegen:gluegen-rt-main", version.ref = "jogl" }
|
||||
flatlaf = { module = "com.formdev:flatlaf", version = "3.4.1" }
|
||||
flatlaf = { module = "com.formdev:flatlaf", version = "2.4" }
|
||||
jna = { module = "net.java.dev.jna:jna", version = "5.12.1" }
|
||||
jnaplatform = { module = "net.java.dev.jna:jna-platform", version = "5.12.1" }
|
||||
compottie = { module = "io.github.alexzhirkevich:compottie", version = "2.0.0-rc02" }
|
||||
kaml = { module = "com.charleskorn.kaml:kaml", version = "0.65.0" }
|
||||
junit = { module = "junit:junit", version = "4.13.2" }
|
||||
junitJupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "jupiter" }
|
||||
junitJupiterParams = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "jupiter" }
|
||||
mockito = { module = "org.mockito:mockito-core", version = "4.11.0" }
|
||||
mockitoKotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.4.0" }
|
||||
antlr = { module = "org.antlr:antlr4", version = "4.7.2" }
|
||||
eclipseJDT = { module = "org.eclipse.jdt:org.eclipse.jdt.core", version = "3.16.0" }
|
||||
eclipseJDTCompiler = { module = "org.eclipse.jdt:org.eclipse.jdt.compiler.apt", version = "1.3.400" }
|
||||
@@ -27,6 +31,8 @@ antlr4Runtime = { module = "org.antlr:antlr4-runtime", version.ref = "antlr" }
|
||||
composeGradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-plugin" }
|
||||
kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
kotlinComposePlugin = { module = "org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin", version.ref = "kotlin" }
|
||||
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" }
|
||||
|
||||
@@ -5,8 +5,6 @@ plugins{
|
||||
id("com.vanniktech.maven.publish") version "0.30.0"
|
||||
}
|
||||
|
||||
group = "org.processing"
|
||||
|
||||
repositories{
|
||||
mavenCentral()
|
||||
google()
|
||||
|
||||
@@ -6,8 +6,6 @@ plugins{
|
||||
alias(libs.plugins.mavenPublish)
|
||||
}
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
repositories{
|
||||
mavenCentral()
|
||||
google()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user