diff --git a/README.md b/README.md index cb44a017..d1048355 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# jMonkeyBuilder 1.8.0 # +# jMonkeyBuilder 1.9.0 # ### It's 3D Editor to prepare/work/create graphics content for jMonkeyEngine 3.2 ### [![Join the chat at https://gitter.im/jME3-SpaceShift-Editor/Lobby](https://badges.gitter.im/jME3-SpaceShift-Editor/Lobby.svg)](https://gitter.im/jME3-SpaceShift-Editor/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/app.version b/app.version index afa2b351..abb16582 100644 --- a/app.version +++ b/app.version @@ -1 +1 @@ -1.8.0 \ No newline at end of file +1.9.0 \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8609991e..ba07de54 100644 --- a/build.gradle +++ b/build.gradle @@ -4,21 +4,19 @@ buildscript { jcenter() } dependencies { - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.1' } } apply plugin: 'java' apply plugin: 'maven' apply plugin: 'idea' -apply plugin: 'org.junit.platform.gradle.plugin' apply plugin: 'com.jfrog.bintray' apply plugin: 'maven-publish' apply plugin: 'application' group = 'com.spaceshift' -version = '1.8.0' +version = '1.9.0' compileJava { options.encoding = "UTF-8" @@ -55,24 +53,13 @@ mainClassName = "com.ss.editor.JfxApplication" ext.applicationMainClass = "com.ss.editor.JfxApplication" ext.applicationVendor = "javasabr@gmail.com" ext.applicationTitle = "jMonkeyBuilder" -ext.jmeVersion = "3.2.1-SNAPSHOT" -ext.jmbExtVersion = "2.3.1" +ext.jmeVersion = "develop-SNAPSHOT" +ext.jmbExtVersion = "2.4.2" ext.jme3_xbuf_version = '0.9.1' -ext.junitPlatformVersion = "1.0.0" -ext.junitJupiterVersion = "5.0.0" +ext.junitJupiterVersion = "5.2.0" ext.log4jVersion = '2.6.2' ext.bintrayVersion = version -junitPlatform { - filters { - engines { - } - tags { - } - } - logManager 'org.apache.logging.log4j.jul.LogManager' -} - repositories { jcenter() mavenCentral() @@ -119,6 +106,18 @@ bintray { } } +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + } + + reports { + html.enabled = true + } +} + javadoc { failOnError = false } @@ -128,14 +127,17 @@ dependencies { // base compile group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.9.0' compile 'org.controlsfx:controlsfx:9.0.0' - compile 'com.spaceshift:rlib.fx:5.0.2' - compile 'com.spaceshift:rlib.common:7.1.2' + compile 'com.spaceshift:rlib.fx:5.1.1' + compile 'com.spaceshift:rlib.common:8.1.1' compile ('com.jme3:jfx:2.0.0') { exclude group: 'org.jmonkeyengine' } // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' + // https://mvnrepository.com/artifact/com.eclipsesource.minimal-json/minimal-json + compile group: 'com.eclipsesource.minimal-json', name: 'minimal-json', version: '0.9.5' + // extend image support // https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-batik @@ -171,6 +173,7 @@ dependencies { // extensions compile ("com.spaceshift:jmonkeybuilder-extension:$jmbExtVersion") { exclude group: 'org.jmonkeyengine' + exclude group: 'com.github.JavaSaB.jmonkeyengine' } compile ("org.xbuf.jme3_xbuf:jme3_xbuf_loader:${jme3_xbuf_version}") { @@ -178,7 +181,7 @@ dependencies { } // https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all - compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.13' + compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.1' // TESTS testRuntime "com.github.JavaSaBr.jmonkeyengine:jme3-lwjgl3:$jmeVersion" @@ -187,17 +190,8 @@ dependencies { exclude group: 'com.github.JavaSaB.jmonkeyengine' } - testCompile "org.junit.platform:junit-platform-commons:$junitPlatformVersion" - testRuntime "org.junit.platform:junit-platform-engine:$junitPlatformVersion" - testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion" testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion" - - testRuntime "org.apache.logging.log4j:log4j-core:$log4jVersion" - testRuntime "org.apache.logging.log4j:log4j-jul:$log4jVersion" - - // Only needed to run tests in an (IntelliJ) IDE(A) that bundles an older version - testCompile "org.junit.platform:junit-platform-launcher:$junitPlatformVersion" } ant.importBuild('build-native.xml') @@ -232,5 +226,6 @@ task javadocJar(type: Jar, dependsOn: javadoc) { } task wrapper(type: Wrapper) { - gradleVersion = '4.7' + gradleVersion = '4.9' + distributionType = Wrapper.DistributionType.ALL } \ No newline at end of file diff --git a/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.1.jar b/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.1.jar deleted file mode 100644 index cd11499d..00000000 Binary files a/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.1.jar and /dev/null differ diff --git a/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.3.jar b/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.3.jar new file mode 100644 index 00000000..9ff1fb6b Binary files /dev/null and b/embedded-plugins/jmb-font-generator/jmb-font-generator-1.1.3.jar differ diff --git a/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar b/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar deleted file mode 100644 index 38de7df3..00000000 Binary files a/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar and /dev/null differ diff --git a/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.1.jar b/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.1.jar deleted file mode 100644 index 10df5a95..00000000 Binary files a/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.1.jar and /dev/null differ diff --git a/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.3.jar b/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.3.jar new file mode 100644 index 00000000..62401a98 Binary files /dev/null and b/embedded-plugins/jmb-sky-control/jmb-sky-control-1.2.3.jar differ diff --git a/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.12.jar b/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.12.jar deleted file mode 100644 index 5f81fd44..00000000 Binary files a/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.12.jar and /dev/null differ diff --git a/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.13.jar b/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.13.jar new file mode 100644 index 00000000..b1827dae Binary files /dev/null and b/embedded-plugins/jmb-sky-control/libs/SkyControl-0.9.13.jar differ diff --git a/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.4.0.jar b/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.4.0.jar deleted file mode 100644 index e7906f82..00000000 Binary files a/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.4.0.jar and /dev/null differ diff --git a/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.5.0.jar b/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.5.0.jar new file mode 100644 index 00000000..199df33e Binary files /dev/null and b/embedded-plugins/jmb-sky-control/libs/jme3-utilities-heart-2.5.0.jar differ diff --git a/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.2.jar b/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.2.jar deleted file mode 100644 index 4655f139..00000000 Binary files a/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.2.jar and /dev/null differ diff --git a/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.4.jar b/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.4.jar new file mode 100644 index 00000000..0e7f7a68 Binary files /dev/null and b/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.1.4.jar differ diff --git a/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.2.jar b/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.2.jar deleted file mode 100644 index a9e47cef..00000000 Binary files a/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.2.jar and /dev/null differ diff --git a/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.3.jar b/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.3.jar new file mode 100644 index 00000000..917be2a8 Binary files /dev/null and b/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.2.3.jar differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 91ca28c8..0d4a9516 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 16d28051..7dc503f1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/libs/common-image-3.3.2.jar b/libs/common-image-3.3.2.jar deleted file mode 100644 index b6452f78..00000000 Binary files a/libs/common-image-3.3.2.jar and /dev/null differ diff --git a/libs/common-io-3.3.2.jar b/libs/common-io-3.3.2.jar deleted file mode 100644 index 4f0ad4af..00000000 Binary files a/libs/common-io-3.3.2.jar and /dev/null differ diff --git a/libs/common-lang-3.3.2.jar b/libs/common-lang-3.3.2.jar deleted file mode 100644 index 65e30018..00000000 Binary files a/libs/common-lang-3.3.2.jar and /dev/null differ diff --git a/libs/commons-lang3-3.4-javadoc.jar b/libs/commons-lang3-3.4-javadoc.jar deleted file mode 100644 index f5c7c593..00000000 Binary files a/libs/commons-lang3-3.4-javadoc.jar and /dev/null differ diff --git a/libs/commons-lang3-3.4.jar b/libs/commons-lang3-3.4.jar deleted file mode 100644 index 8ec91d45..00000000 Binary files a/libs/commons-lang3-3.4.jar and /dev/null differ diff --git a/libs/extensions/annotations-15.0.jar b/libs/extensions/annotations-15.0.jar deleted file mode 100644 index 3f838329..00000000 Binary files a/libs/extensions/annotations-15.0.jar and /dev/null differ diff --git a/libs/extensions/groovy-all-2.5.0-alpha-1.jar b/libs/extensions/groovy-all-2.5.0-alpha-1.jar deleted file mode 100644 index 77cb9932..00000000 Binary files a/libs/extensions/groovy-all-2.5.0-alpha-1.jar and /dev/null differ diff --git a/libs/extensions/jme3-spaceshift-extension-1.0.1-sources.jar b/libs/extensions/jme3-spaceshift-extension-1.0.1-sources.jar deleted file mode 100644 index a6509880..00000000 Binary files a/libs/extensions/jme3-spaceshift-extension-1.0.1-sources.jar and /dev/null differ diff --git a/libs/extensions/jme3-spaceshift-extension-1.0.1.jar b/libs/extensions/jme3-spaceshift-extension-1.0.1.jar deleted file mode 100644 index a958b7a1..00000000 Binary files a/libs/extensions/jme3-spaceshift-extension-1.0.1.jar and /dev/null differ diff --git a/libs/extensions/rlib-6.1.2-sources.jar b/libs/extensions/rlib-6.1.2-sources.jar deleted file mode 100644 index de0b710b..00000000 Binary files a/libs/extensions/rlib-6.1.2-sources.jar and /dev/null differ diff --git a/libs/extensions/rlib-6.1.2.jar b/libs/extensions/rlib-6.1.2.jar deleted file mode 100644 index e5a49cca..00000000 Binary files a/libs/extensions/rlib-6.1.2.jar and /dev/null differ diff --git a/libs/extensions/simsilica/iso-surface-sources.1.0.0.jar b/libs/extensions/simsilica/iso-surface-sources.1.0.0.jar deleted file mode 100644 index bfc9fad6..00000000 Binary files a/libs/extensions/simsilica/iso-surface-sources.1.0.0.jar and /dev/null differ diff --git a/libs/extensions/simsilica/iso-surface.1.0.0.jar b/libs/extensions/simsilica/iso-surface.1.0.0.jar deleted file mode 100644 index c356fe1a..00000000 Binary files a/libs/extensions/simsilica/iso-surface.1.0.0.jar and /dev/null differ diff --git a/libs/extensions/simsilica/lemur-1.9.1-sources.jar b/libs/extensions/simsilica/lemur-1.9.1-sources.jar deleted file mode 100644 index 390329cc..00000000 Binary files a/libs/extensions/simsilica/lemur-1.9.1-sources.jar and /dev/null differ diff --git a/libs/extensions/simsilica/lemur-1.9.1.jar b/libs/extensions/simsilica/lemur-1.9.1.jar deleted file mode 100644 index 8ec06437..00000000 Binary files a/libs/extensions/simsilica/lemur-1.9.1.jar and /dev/null differ diff --git a/libs/extensions/simsilica/sim-fx-1.0.4-sources.jar b/libs/extensions/simsilica/sim-fx-1.0.4-sources.jar deleted file mode 100644 index 7bdb8181..00000000 Binary files a/libs/extensions/simsilica/sim-fx-1.0.4-sources.jar and /dev/null differ diff --git a/libs/extensions/simsilica/sim-fx-1.0.4.jar b/libs/extensions/simsilica/sim-fx-1.0.4.jar deleted file mode 100644 index 7a6a8ced..00000000 Binary files a/libs/extensions/simsilica/sim-fx-1.0.4.jar and /dev/null differ diff --git a/libs/extensions/toneg0d/toneg0d.emitter-2.2.3-sources.jar b/libs/extensions/toneg0d/toneg0d.emitter-2.2.3-sources.jar deleted file mode 100644 index f292612d..00000000 Binary files a/libs/extensions/toneg0d/toneg0d.emitter-2.2.3-sources.jar and /dev/null differ diff --git a/libs/extensions/toneg0d/toneg0d.emitter-2.2.3.jar b/libs/extensions/toneg0d/toneg0d.emitter-2.2.3.jar deleted file mode 100644 index 50839ea2..00000000 Binary files a/libs/extensions/toneg0d/toneg0d.emitter-2.2.3.jar and /dev/null differ diff --git a/libs/extensions/xbuf/guava-18.0.jar b/libs/extensions/xbuf/guava-18.0.jar deleted file mode 100644 index 8f89e490..00000000 Binary files a/libs/extensions/xbuf/guava-18.0.jar and /dev/null differ diff --git a/libs/extensions/xbuf/jme3_physicsloader-0.5.jar b/libs/extensions/xbuf/jme3_physicsloader-0.5.jar deleted file mode 100644 index 6c81ce62..00000000 Binary files a/libs/extensions/xbuf/jme3_physicsloader-0.5.jar and /dev/null differ diff --git a/libs/extensions/xbuf/jme3_xbuf_loader-0.9.1.jar b/libs/extensions/xbuf/jme3_xbuf_loader-0.9.1.jar deleted file mode 100644 index f9c1ef0c..00000000 Binary files a/libs/extensions/xbuf/jme3_xbuf_loader-0.9.1.jar and /dev/null differ diff --git a/libs/extensions/xbuf/jme3_xbuf_rt-0.9.1.jar b/libs/extensions/xbuf/jme3_xbuf_rt-0.9.1.jar deleted file mode 100644 index 8e3dede4..00000000 Binary files a/libs/extensions/xbuf/jme3_xbuf_rt-0.9.1.jar and /dev/null differ diff --git a/libs/extensions/xbuf/protobuf-java-3.0.0.jar b/libs/extensions/xbuf/protobuf-java-3.0.0.jar deleted file mode 100644 index 7f36b334..00000000 Binary files a/libs/extensions/xbuf/protobuf-java-3.0.0.jar and /dev/null differ diff --git a/libs/extensions/xbuf/protobuf-java-util-3.0.0.jar b/libs/extensions/xbuf/protobuf-java-util-3.0.0.jar deleted file mode 100644 index 81363166..00000000 Binary files a/libs/extensions/xbuf/protobuf-java-util-3.0.0.jar and /dev/null differ diff --git a/libs/extensions/xbuf/slf4j-api-1.7.25.jar b/libs/extensions/xbuf/slf4j-api-1.7.25.jar deleted file mode 100644 index 0143c099..00000000 Binary files a/libs/extensions/xbuf/slf4j-api-1.7.25.jar and /dev/null differ diff --git a/libs/extensions/xbuf/slf4j-simple-1.7.25.jar b/libs/extensions/xbuf/slf4j-simple-1.7.25.jar deleted file mode 100644 index a7260f3d..00000000 Binary files a/libs/extensions/xbuf/slf4j-simple-1.7.25.jar and /dev/null differ diff --git a/libs/extensions/xbuf/xbuf-0.9.1.jar b/libs/extensions/xbuf/xbuf-0.9.1.jar deleted file mode 100644 index 0d733845..00000000 Binary files a/libs/extensions/xbuf/xbuf-0.9.1.jar and /dev/null differ diff --git a/libs/gson-2.6.2.jar b/libs/gson-2.6.2.jar deleted file mode 100644 index 9d78626d..00000000 Binary files a/libs/gson-2.6.2.jar and /dev/null differ diff --git a/libs/http/commons-codec-1.9.jar b/libs/http/commons-codec-1.9.jar deleted file mode 100644 index ef35f1c5..00000000 Binary files a/libs/http/commons-codec-1.9.jar and /dev/null differ diff --git a/libs/http/commons-logging-1.2.jar b/libs/http/commons-logging-1.2.jar deleted file mode 100644 index 93a3b9f6..00000000 Binary files a/libs/http/commons-logging-1.2.jar and /dev/null differ diff --git a/libs/http/httpclient-4.5.2.jar b/libs/http/httpclient-4.5.2.jar deleted file mode 100644 index 701609fc..00000000 Binary files a/libs/http/httpclient-4.5.2.jar and /dev/null differ diff --git a/libs/http/httpcore-4.4.4.jar b/libs/http/httpcore-4.4.4.jar deleted file mode 100644 index ac4a8773..00000000 Binary files a/libs/http/httpcore-4.4.4.jar and /dev/null differ diff --git a/libs/imageio-batik-3.3.2.jar b/libs/imageio-batik-3.3.2.jar deleted file mode 100644 index 8cc8d286..00000000 Binary files a/libs/imageio-batik-3.3.2.jar and /dev/null differ diff --git a/libs/imageio-core-3.3.2.jar b/libs/imageio-core-3.3.2.jar deleted file mode 100644 index cff75070..00000000 Binary files a/libs/imageio-core-3.3.2.jar and /dev/null differ diff --git a/libs/imageio-hdr-3.3.2.jar b/libs/imageio-hdr-3.3.2.jar deleted file mode 100644 index 8f6a6e36..00000000 Binary files a/libs/imageio-hdr-3.3.2.jar and /dev/null differ diff --git a/libs/imageio-metadata-3.3.2.jar b/libs/imageio-metadata-3.3.2.jar deleted file mode 100644 index 2d7e4962..00000000 Binary files a/libs/imageio-metadata-3.3.2.jar and /dev/null differ diff --git a/libs/imageio-tiff-3.3.2.jar b/libs/imageio-tiff-3.3.2.jar deleted file mode 100644 index 7574dc54..00000000 Binary files a/libs/imageio-tiff-3.3.2.jar and /dev/null differ diff --git a/libs/jME/core-0.27.jar b/libs/jME/core-0.27.jar deleted file mode 100644 index 2cfecd5a..00000000 Binary files a/libs/jME/core-0.27.jar and /dev/null differ diff --git a/libs/jME/dense64-0.27.jar b/libs/jME/dense64-0.27.jar deleted file mode 100644 index 8143896f..00000000 Binary files a/libs/jME/dense64-0.27.jar and /dev/null differ diff --git a/libs/jME/denseC64-0.27.jar b/libs/jME/denseC64-0.27.jar deleted file mode 100644 index 8b8ce8d9..00000000 Binary files a/libs/jME/denseC64-0.27.jar and /dev/null differ diff --git a/libs/jME/eventbus-1.4.jar b/libs/jME/eventbus-1.4.jar deleted file mode 100644 index 4da3e24e..00000000 Binary files a/libs/jME/eventbus-1.4.jar and /dev/null differ diff --git a/libs/jME/j-ogg-all-1.0.0.jar b/libs/jME/j-ogg-all-1.0.0.jar deleted file mode 100644 index 73c983da..00000000 Binary files a/libs/jME/j-ogg-all-1.0.0.jar and /dev/null differ diff --git a/libs/jME/jbullet.jar b/libs/jME/jbullet.jar deleted file mode 100644 index 4e158f10..00000000 Binary files a/libs/jME/jbullet.jar and /dev/null differ diff --git a/libs/jME/jglfont-core-1.4.jar b/libs/jME/jglfont-core-1.4.jar deleted file mode 100644 index 756d955e..00000000 Binary files a/libs/jME/jglfont-core-1.4.jar and /dev/null differ diff --git a/libs/jME/jinput-2.0.5.jar b/libs/jME/jinput-2.0.5.jar deleted file mode 100644 index cc8428d6..00000000 Binary files a/libs/jME/jinput-2.0.5.jar and /dev/null differ diff --git a/libs/jME/jinput-platform-2.0.5-natives-linux.jar b/libs/jME/jinput-platform-2.0.5-natives-linux.jar deleted file mode 100644 index 10194cf2..00000000 Binary files a/libs/jME/jinput-platform-2.0.5-natives-linux.jar and /dev/null differ diff --git a/libs/jME/jinput-platform-2.0.5-natives-osx.jar b/libs/jME/jinput-platform-2.0.5-natives-osx.jar deleted file mode 100644 index a6d8a4f5..00000000 Binary files a/libs/jME/jinput-platform-2.0.5-natives-osx.jar and /dev/null differ diff --git a/libs/jME/jinput-platform-2.0.5-natives-windows.jar b/libs/jME/jinput-platform-2.0.5-natives-windows.jar deleted file mode 100644 index b9c079e6..00000000 Binary files a/libs/jME/jinput-platform-2.0.5-natives-windows.jar and /dev/null differ diff --git a/libs/jME/jme3-blender-3.2.0-sources.jar b/libs/jME/jme3-blender-3.2.0-sources.jar deleted file mode 100644 index 800a6e55..00000000 Binary files a/libs/jME/jme3-blender-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-blender-3.2.0.jar b/libs/jME/jme3-blender-3.2.0.jar deleted file mode 100644 index 991e95e9..00000000 Binary files a/libs/jME/jme3-blender-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-bullet-3.2.0-sources.jar b/libs/jME/jme3-bullet-3.2.0-sources.jar deleted file mode 100644 index 79ed4c25..00000000 Binary files a/libs/jME/jme3-bullet-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-bullet-3.2.0.jar b/libs/jME/jme3-bullet-3.2.0.jar deleted file mode 100644 index 06c45049..00000000 Binary files a/libs/jME/jme3-bullet-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-bullet-native-3.2.0-sources.jar b/libs/jME/jme3-bullet-native-3.2.0-sources.jar deleted file mode 100644 index f5df9709..00000000 Binary files a/libs/jME/jme3-bullet-native-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-bullet-native-3.2.0.jar b/libs/jME/jme3-bullet-native-3.2.0.jar deleted file mode 100644 index 954ba3f4..00000000 Binary files a/libs/jME/jme3-bullet-native-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-core-3.2.0-sources.jar b/libs/jME/jme3-core-3.2.0-sources.jar deleted file mode 100644 index 3a8c9a1e..00000000 Binary files a/libs/jME/jme3-core-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-core-3.2.0.jar b/libs/jME/jme3-core-3.2.0.jar deleted file mode 100644 index 4d3deac3..00000000 Binary files a/libs/jME/jme3-core-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-desktop-3.2.0-sources.jar b/libs/jME/jme3-desktop-3.2.0-sources.jar deleted file mode 100644 index 92347e51..00000000 Binary files a/libs/jME/jme3-desktop-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-desktop-3.2.0.jar b/libs/jME/jme3-desktop-3.2.0.jar deleted file mode 100644 index 13d89f60..00000000 Binary files a/libs/jME/jme3-desktop-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-effects-3.2.0-sources.jar b/libs/jME/jme3-effects-3.2.0-sources.jar deleted file mode 100644 index 421c4a8c..00000000 Binary files a/libs/jME/jme3-effects-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-effects-3.2.0.jar b/libs/jME/jme3-effects-3.2.0.jar deleted file mode 100644 index af051192..00000000 Binary files a/libs/jME/jme3-effects-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-jogg-3.2.0-sources.jar b/libs/jME/jme3-jogg-3.2.0-sources.jar deleted file mode 100644 index 52d48266..00000000 Binary files a/libs/jME/jme3-jogg-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-jogg-3.2.0.jar b/libs/jME/jme3-jogg-3.2.0.jar deleted file mode 100644 index dbfad488..00000000 Binary files a/libs/jME/jme3-jogg-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-lwjgl3-3.2.0-sources.jar b/libs/jME/jme3-lwjgl3-3.2.0-sources.jar deleted file mode 100644 index 272cb1f3..00000000 Binary files a/libs/jME/jme3-lwjgl3-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-lwjgl3-3.2.0.jar b/libs/jME/jme3-lwjgl3-3.2.0.jar deleted file mode 100644 index e44063a8..00000000 Binary files a/libs/jME/jme3-lwjgl3-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-plugins-3.2.0-sources.jar b/libs/jME/jme3-plugins-3.2.0-sources.jar deleted file mode 100644 index 360a525a..00000000 Binary files a/libs/jME/jme3-plugins-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-plugins-3.2.0.jar b/libs/jME/jme3-plugins-3.2.0.jar deleted file mode 100644 index 9851dd71..00000000 Binary files a/libs/jME/jme3-plugins-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jme3-terrain-3.2.0-sources.jar b/libs/jME/jme3-terrain-3.2.0-sources.jar deleted file mode 100644 index a64363db..00000000 Binary files a/libs/jME/jme3-terrain-3.2.0-sources.jar and /dev/null differ diff --git a/libs/jME/jme3-terrain-3.2.0.jar b/libs/jME/jme3-terrain-3.2.0.jar deleted file mode 100644 index 0623069f..00000000 Binary files a/libs/jME/jme3-terrain-3.2.0.jar and /dev/null differ diff --git a/libs/jME/jsr305-2.0.2.jar b/libs/jME/jsr305-2.0.2.jar deleted file mode 100644 index 18163e68..00000000 Binary files a/libs/jME/jsr305-2.0.2.jar and /dev/null differ diff --git a/libs/jME/jutils-1.0.0.jar b/libs/jME/jutils-1.0.0.jar deleted file mode 100644 index cf407cfd..00000000 Binary files a/libs/jME/jutils-1.0.0.jar and /dev/null differ diff --git a/libs/jME/lwjgl-glfw-natives-linux.jar b/libs/jME/lwjgl-glfw-natives-linux.jar deleted file mode 100644 index 56722dec..00000000 Binary files a/libs/jME/lwjgl-glfw-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-glfw-natives-macos.jar b/libs/jME/lwjgl-glfw-natives-macos.jar deleted file mode 100644 index 24f83e14..00000000 Binary files a/libs/jME/lwjgl-glfw-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-glfw-natives-windows.jar b/libs/jME/lwjgl-glfw-natives-windows.jar deleted file mode 100644 index 6ac6e799..00000000 Binary files a/libs/jME/lwjgl-glfw-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-glfw-sources.jar b/libs/jME/lwjgl-glfw-sources.jar deleted file mode 100644 index 6e37d16d..00000000 Binary files a/libs/jME/lwjgl-glfw-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-glfw.jar b/libs/jME/lwjgl-glfw.jar deleted file mode 100644 index 39cb479e..00000000 Binary files a/libs/jME/lwjgl-glfw.jar and /dev/null differ diff --git a/libs/jME/lwjgl-jemalloc-natives-linux.jar b/libs/jME/lwjgl-jemalloc-natives-linux.jar deleted file mode 100644 index 622f9615..00000000 Binary files a/libs/jME/lwjgl-jemalloc-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-jemalloc-natives-macos.jar b/libs/jME/lwjgl-jemalloc-natives-macos.jar deleted file mode 100644 index ba6f734d..00000000 Binary files a/libs/jME/lwjgl-jemalloc-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-jemalloc-natives-windows.jar b/libs/jME/lwjgl-jemalloc-natives-windows.jar deleted file mode 100644 index 4d6f647e..00000000 Binary files a/libs/jME/lwjgl-jemalloc-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-jemalloc-sources.jar b/libs/jME/lwjgl-jemalloc-sources.jar deleted file mode 100644 index 621f10a3..00000000 Binary files a/libs/jME/lwjgl-jemalloc-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-jemalloc.jar b/libs/jME/lwjgl-jemalloc.jar deleted file mode 100644 index d2286b32..00000000 Binary files a/libs/jME/lwjgl-jemalloc.jar and /dev/null differ diff --git a/libs/jME/lwjgl-natives-linux.jar b/libs/jME/lwjgl-natives-linux.jar deleted file mode 100644 index fcc72742..00000000 Binary files a/libs/jME/lwjgl-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-natives-macos.jar b/libs/jME/lwjgl-natives-macos.jar deleted file mode 100644 index 9de309da..00000000 Binary files a/libs/jME/lwjgl-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-natives-windows.jar b/libs/jME/lwjgl-natives-windows.jar deleted file mode 100644 index 163a706f..00000000 Binary files a/libs/jME/lwjgl-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-openal-natives-linux.jar b/libs/jME/lwjgl-openal-natives-linux.jar deleted file mode 100644 index 77da6324..00000000 Binary files a/libs/jME/lwjgl-openal-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-openal-natives-macos.jar b/libs/jME/lwjgl-openal-natives-macos.jar deleted file mode 100644 index f169b696..00000000 Binary files a/libs/jME/lwjgl-openal-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-openal-natives-windows.jar b/libs/jME/lwjgl-openal-natives-windows.jar deleted file mode 100644 index b1e674de..00000000 Binary files a/libs/jME/lwjgl-openal-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-openal-sources.jar b/libs/jME/lwjgl-openal-sources.jar deleted file mode 100644 index ddb3883e..00000000 Binary files a/libs/jME/lwjgl-openal-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-openal.jar b/libs/jME/lwjgl-openal.jar deleted file mode 100644 index 1f2407f4..00000000 Binary files a/libs/jME/lwjgl-openal.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opencl-sources.jar b/libs/jME/lwjgl-opencl-sources.jar deleted file mode 100644 index c58ecdec..00000000 Binary files a/libs/jME/lwjgl-opencl-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opencl.jar b/libs/jME/lwjgl-opencl.jar deleted file mode 100644 index af07fd20..00000000 Binary files a/libs/jME/lwjgl-opencl.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opengl-natives-linux.jar b/libs/jME/lwjgl-opengl-natives-linux.jar deleted file mode 100644 index 433dbb83..00000000 Binary files a/libs/jME/lwjgl-opengl-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opengl-natives-macos.jar b/libs/jME/lwjgl-opengl-natives-macos.jar deleted file mode 100644 index e38c09cb..00000000 Binary files a/libs/jME/lwjgl-opengl-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opengl-natives-windows.jar b/libs/jME/lwjgl-opengl-natives-windows.jar deleted file mode 100644 index 223104e9..00000000 Binary files a/libs/jME/lwjgl-opengl-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opengl-sources.jar b/libs/jME/lwjgl-opengl-sources.jar deleted file mode 100644 index f157f985..00000000 Binary files a/libs/jME/lwjgl-opengl-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-opengl.jar b/libs/jME/lwjgl-opengl.jar deleted file mode 100644 index 8ed0165d..00000000 Binary files a/libs/jME/lwjgl-opengl.jar and /dev/null differ diff --git a/libs/jME/lwjgl-sources.jar b/libs/jME/lwjgl-sources.jar deleted file mode 100644 index 30a44ca2..00000000 Binary files a/libs/jME/lwjgl-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-stb-natives-linux.jar b/libs/jME/lwjgl-stb-natives-linux.jar deleted file mode 100644 index 04db9a51..00000000 Binary files a/libs/jME/lwjgl-stb-natives-linux.jar and /dev/null differ diff --git a/libs/jME/lwjgl-stb-natives-macos.jar b/libs/jME/lwjgl-stb-natives-macos.jar deleted file mode 100644 index dce4366e..00000000 Binary files a/libs/jME/lwjgl-stb-natives-macos.jar and /dev/null differ diff --git a/libs/jME/lwjgl-stb-natives-windows.jar b/libs/jME/lwjgl-stb-natives-windows.jar deleted file mode 100644 index c5acef89..00000000 Binary files a/libs/jME/lwjgl-stb-natives-windows.jar and /dev/null differ diff --git a/libs/jME/lwjgl-stb-sources.jar b/libs/jME/lwjgl-stb-sources.jar deleted file mode 100644 index eb97c857..00000000 Binary files a/libs/jME/lwjgl-stb-sources.jar and /dev/null differ diff --git a/libs/jME/lwjgl-stb.jar b/libs/jME/lwjgl-stb.jar deleted file mode 100644 index 578151f4..00000000 Binary files a/libs/jME/lwjgl-stb.jar and /dev/null differ diff --git a/libs/jME/lwjgl.jar b/libs/jME/lwjgl.jar deleted file mode 100644 index c1eaa82d..00000000 Binary files a/libs/jME/lwjgl.jar and /dev/null differ diff --git a/libs/jME/retrace.jar b/libs/jME/retrace.jar deleted file mode 100644 index c26d40cf..00000000 Binary files a/libs/jME/retrace.jar and /dev/null differ diff --git a/libs/jME/simple-0.27.jar b/libs/jME/simple-0.27.jar deleted file mode 100644 index 3911edd7..00000000 Binary files a/libs/jME/simple-0.27.jar and /dev/null differ diff --git a/libs/jME/stack-alloc.jar b/libs/jME/stack-alloc.jar deleted file mode 100644 index 3bd50f74..00000000 Binary files a/libs/jME/stack-alloc.jar and /dev/null differ diff --git a/libs/jME/vecmath-1.3.1.jar b/libs/jME/vecmath-1.3.1.jar deleted file mode 100644 index c5a756a6..00000000 Binary files a/libs/jME/vecmath-1.3.1.jar and /dev/null differ diff --git a/libs/jME/xpp3-1.1.4c.jar b/libs/jME/xpp3-1.1.4c.jar deleted file mode 100644 index a44765e0..00000000 Binary files a/libs/jME/xpp3-1.1.4c.jar and /dev/null differ diff --git a/libs/jme-jfx-1.5.2-sources.jar b/libs/jme-jfx-1.5.2-sources.jar deleted file mode 100644 index 757760f7..00000000 Binary files a/libs/jme-jfx-1.5.2-sources.jar and /dev/null differ diff --git a/libs/jme-jfx-1.5.2.jar b/libs/jme-jfx-1.5.2.jar deleted file mode 100644 index a68a8c07..00000000 Binary files a/libs/jme-jfx-1.5.2.jar and /dev/null differ diff --git a/libs/richtextfx-0.7-M5-sources.jar b/libs/richtextfx-0.7-M5-sources.jar deleted file mode 100644 index d51809e6..00000000 Binary files a/libs/richtextfx-0.7-M5-sources.jar and /dev/null differ diff --git a/libs/richtextfx-fat-0.7-M5.jar b/libs/richtextfx-fat-0.7-M5.jar deleted file mode 100644 index 3018881b..00000000 Binary files a/libs/richtextfx-fat-0.7-M5.jar and /dev/null differ diff --git a/libs/rlib-fx-4.1.2-sources.jar b/libs/rlib-fx-4.1.2-sources.jar deleted file mode 100644 index 97f94427..00000000 Binary files a/libs/rlib-fx-4.1.2-sources.jar and /dev/null differ diff --git a/libs/rlib-fx-4.1.2.jar b/libs/rlib-fx-4.1.2.jar deleted file mode 100644 index 47480ecf..00000000 Binary files a/libs/rlib-fx-4.1.2.jar and /dev/null differ diff --git a/libs/svg/avalon-framework-4.1.3.jar b/libs/svg/avalon-framework-4.1.3.jar deleted file mode 100644 index fd72580d..00000000 Binary files a/libs/svg/avalon-framework-4.1.3.jar and /dev/null differ diff --git a/libs/svg/batik-anim-1.8-sources.jar b/libs/svg/batik-anim-1.8-sources.jar deleted file mode 100644 index 7bd3d346..00000000 Binary files a/libs/svg/batik-anim-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-anim-1.8.jar b/libs/svg/batik-anim-1.8.jar deleted file mode 100644 index 3f1a185a..00000000 Binary files a/libs/svg/batik-anim-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-awt-util-1.8-sources.jar b/libs/svg/batik-awt-util-1.8-sources.jar deleted file mode 100644 index 13c53da7..00000000 Binary files a/libs/svg/batik-awt-util-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-awt-util-1.8.jar b/libs/svg/batik-awt-util-1.8.jar deleted file mode 100644 index ce0be3cd..00000000 Binary files a/libs/svg/batik-awt-util-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-bridge-1.8-sources.jar b/libs/svg/batik-bridge-1.8-sources.jar deleted file mode 100644 index da7f3dc5..00000000 Binary files a/libs/svg/batik-bridge-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-bridge-1.8.jar b/libs/svg/batik-bridge-1.8.jar deleted file mode 100644 index f9fc68e1..00000000 Binary files a/libs/svg/batik-bridge-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-css-1.8-sources.jar b/libs/svg/batik-css-1.8-sources.jar deleted file mode 100644 index a202bed6..00000000 Binary files a/libs/svg/batik-css-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-css-1.8.jar b/libs/svg/batik-css-1.8.jar deleted file mode 100644 index 1cf2736e..00000000 Binary files a/libs/svg/batik-css-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-dom-1.8-sources.jar b/libs/svg/batik-dom-1.8-sources.jar deleted file mode 100644 index d034e401..00000000 Binary files a/libs/svg/batik-dom-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-dom-1.8.jar b/libs/svg/batik-dom-1.8.jar deleted file mode 100644 index 51d88f6a..00000000 Binary files a/libs/svg/batik-dom-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-ext-1.8-sources.jar b/libs/svg/batik-ext-1.8-sources.jar deleted file mode 100644 index 2f8d4d56..00000000 Binary files a/libs/svg/batik-ext-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-ext-1.8.jar b/libs/svg/batik-ext-1.8.jar deleted file mode 100644 index 6a09ca36..00000000 Binary files a/libs/svg/batik-ext-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-gvt-1.8-sources.jar b/libs/svg/batik-gvt-1.8-sources.jar deleted file mode 100644 index 1f23133c..00000000 Binary files a/libs/svg/batik-gvt-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-gvt-1.8.jar b/libs/svg/batik-gvt-1.8.jar deleted file mode 100644 index e3a00382..00000000 Binary files a/libs/svg/batik-gvt-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-parser-1.8-sources.jar b/libs/svg/batik-parser-1.8-sources.jar deleted file mode 100644 index 16127628..00000000 Binary files a/libs/svg/batik-parser-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-parser-1.8.jar b/libs/svg/batik-parser-1.8.jar deleted file mode 100644 index 01108ad7..00000000 Binary files a/libs/svg/batik-parser-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-script-1.8-sources.jar b/libs/svg/batik-script-1.8-sources.jar deleted file mode 100644 index e3178d61..00000000 Binary files a/libs/svg/batik-script-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-script-1.8.jar b/libs/svg/batik-script-1.8.jar deleted file mode 100644 index df0face7..00000000 Binary files a/libs/svg/batik-script-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-svg-dom-1.8-sources.jar b/libs/svg/batik-svg-dom-1.8-sources.jar deleted file mode 100644 index 838be351..00000000 Binary files a/libs/svg/batik-svg-dom-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-svg-dom-1.8.jar b/libs/svg/batik-svg-dom-1.8.jar deleted file mode 100644 index 8d7a9046..00000000 Binary files a/libs/svg/batik-svg-dom-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-svggen-1.8-sources.jar b/libs/svg/batik-svggen-1.8-sources.jar deleted file mode 100644 index b1c58563..00000000 Binary files a/libs/svg/batik-svggen-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-svggen-1.8.jar b/libs/svg/batik-svggen-1.8.jar deleted file mode 100644 index aebf1615..00000000 Binary files a/libs/svg/batik-svggen-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-transcoder-1.8-sources.jar b/libs/svg/batik-transcoder-1.8-sources.jar deleted file mode 100644 index 3a444561..00000000 Binary files a/libs/svg/batik-transcoder-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-transcoder-1.8.jar b/libs/svg/batik-transcoder-1.8.jar deleted file mode 100644 index aff308fc..00000000 Binary files a/libs/svg/batik-transcoder-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-util-1.8-sources.jar b/libs/svg/batik-util-1.8-sources.jar deleted file mode 100644 index a442991d..00000000 Binary files a/libs/svg/batik-util-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-util-1.8.jar b/libs/svg/batik-util-1.8.jar deleted file mode 100644 index cb1c63f1..00000000 Binary files a/libs/svg/batik-util-1.8.jar and /dev/null differ diff --git a/libs/svg/batik-xml-1.8-sources.jar b/libs/svg/batik-xml-1.8-sources.jar deleted file mode 100644 index 8486eb38..00000000 Binary files a/libs/svg/batik-xml-1.8-sources.jar and /dev/null differ diff --git a/libs/svg/batik-xml-1.8.jar b/libs/svg/batik-xml-1.8.jar deleted file mode 100644 index 9b02e6c3..00000000 Binary files a/libs/svg/batik-xml-1.8.jar and /dev/null differ diff --git a/libs/svg/commons-io-1.3.1-sources.jar b/libs/svg/commons-io-1.3.1-sources.jar deleted file mode 100644 index e5d78e9d..00000000 Binary files a/libs/svg/commons-io-1.3.1-sources.jar and /dev/null differ diff --git a/libs/svg/commons-io-1.3.1.jar b/libs/svg/commons-io-1.3.1.jar deleted file mode 100644 index 7affdefc..00000000 Binary files a/libs/svg/commons-io-1.3.1.jar and /dev/null differ diff --git a/libs/svg/commons-logging-1.0.4-sources.jar b/libs/svg/commons-logging-1.0.4-sources.jar deleted file mode 100644 index fc4bc9fc..00000000 Binary files a/libs/svg/commons-logging-1.0.4-sources.jar and /dev/null differ diff --git a/libs/svg/commons-logging-1.0.4.jar b/libs/svg/commons-logging-1.0.4.jar deleted file mode 100644 index b73a80fa..00000000 Binary files a/libs/svg/commons-logging-1.0.4.jar and /dev/null differ diff --git a/libs/svg/javafxsvg-1.2.1-sources.jar b/libs/svg/javafxsvg-1.2.1-sources.jar deleted file mode 100644 index e7237655..00000000 Binary files a/libs/svg/javafxsvg-1.2.1-sources.jar and /dev/null differ diff --git a/libs/svg/javafxsvg-1.2.1.jar b/libs/svg/javafxsvg-1.2.1.jar deleted file mode 100644 index d30cf3ee..00000000 Binary files a/libs/svg/javafxsvg-1.2.1.jar and /dev/null differ diff --git a/libs/svg/log4j-1.2.6.jar b/libs/svg/log4j-1.2.6.jar deleted file mode 100644 index be4a9176..00000000 Binary files a/libs/svg/log4j-1.2.6.jar and /dev/null differ diff --git a/libs/svg/logkit-1.0.1-sources.jar b/libs/svg/logkit-1.0.1-sources.jar deleted file mode 100644 index f870617f..00000000 Binary files a/libs/svg/logkit-1.0.1-sources.jar and /dev/null differ diff --git a/libs/svg/logkit-1.0.1.jar b/libs/svg/logkit-1.0.1.jar deleted file mode 100644 index d3250ee6..00000000 Binary files a/libs/svg/logkit-1.0.1.jar and /dev/null differ diff --git a/libs/svg/xalan-2.7.0-sources.jar b/libs/svg/xalan-2.7.0-sources.jar deleted file mode 100644 index dd8fa51b..00000000 Binary files a/libs/svg/xalan-2.7.0-sources.jar and /dev/null differ diff --git a/libs/svg/xalan-2.7.0.jar b/libs/svg/xalan-2.7.0.jar deleted file mode 100644 index 007be396..00000000 Binary files a/libs/svg/xalan-2.7.0.jar and /dev/null differ diff --git a/libs/svg/xml-apis-1.3.04-source.jar b/libs/svg/xml-apis-1.3.04-source.jar deleted file mode 100644 index d9c82cdc..00000000 Binary files a/libs/svg/xml-apis-1.3.04-source.jar and /dev/null differ diff --git a/libs/svg/xml-apis-1.3.04.jar b/libs/svg/xml-apis-1.3.04.jar deleted file mode 100644 index d42c0ea6..00000000 Binary files a/libs/svg/xml-apis-1.3.04.jar and /dev/null differ diff --git a/libs/svg/xml-apis-ext-1.3.04.jar b/libs/svg/xml-apis-ext-1.3.04.jar deleted file mode 100644 index a7869d68..00000000 Binary files a/libs/svg/xml-apis-ext-1.3.04.jar and /dev/null differ diff --git a/libs/svg/xmlgraphics-commons-2.1-sources.jar b/libs/svg/xmlgraphics-commons-2.1-sources.jar deleted file mode 100644 index e3d44641..00000000 Binary files a/libs/svg/xmlgraphics-commons-2.1-sources.jar and /dev/null differ diff --git a/libs/svg/xmlgraphics-commons-2.1.jar b/libs/svg/xmlgraphics-commons-2.1.jar deleted file mode 100644 index f917ca1b..00000000 Binary files a/libs/svg/xmlgraphics-commons-2.1.jar and /dev/null differ diff --git a/src/main/java/com/jme3/scene/Spatial.java b/src/main/java/com/jme3/scene/Spatial.java index 534f46c7..c0df8334 100644 --- a/src/main/java/com/jme3/scene/Spatial.java +++ b/src/main/java/com/jme3/scene/Spatial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2013 jMonkeyEngine + * Copyright (c) 2009-2018 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +31,7 @@ */ package com.jme3.scene; +import com.jme3.anim.util.HasLocalTransform; import com.jme3.asset.AssetKey; import com.jme3.asset.CloneableSmartAsset; import com.jme3.bounding.BoundingVolume; @@ -48,18 +49,18 @@ import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.control.Control; +import com.jme3.util.SafeArrayList; +import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.IdentityCloneFunction; import com.jme3.util.clone.JmeCloneable; -import com.jme3.util.SafeArrayList; -import com.jme3.util.TempVars; import java.io.IOException; import java.util.*; import java.util.logging.Logger; /** * Spatial defines the base class for scene graph nodes. It - * maintains a link to a parent, it's local transforms and the world's + * maintains a link to a parent, its local transforms and the world's * transforms. All other scene graph elements, such as {@link Node} and * {@link Geometry} are subclasses of Spatial. * @@ -67,7 +68,7 @@ * @author Joshua Slack * @version $Revision: 4075 $, $Data$ */ -public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable { +public abstract class Spatial implements Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable, HasLocalTransform { private static final Logger logger = Logger.getLogger(Spatial.class.getName()); @@ -573,8 +574,8 @@ public void lookAt(Vector3f position, Vector3f upVector) { * Should be overridden by Node and Geometry. */ protected void updateWorldBound() { - // the world bound of a leaf is the same as it's model bound - // for a node, the world bound is a combination of all it's children + // the world bound of a leaf is the same as its model bound + // for a node, the world bound is a combination of all its children // bounds // -> handled by subclass refreshFlags &= ~RF_BOUND; @@ -972,7 +973,7 @@ protected void setParent(Node parent) { } /** - * removeFromParent removes this Spatial from it's parent. + * removeFromParent removes this Spatial from its parent. * * @return true if it has a parent and performed the remove. */ @@ -1373,66 +1374,11 @@ public Spatial clone( boolean cloneMaterial ) { } /** - * The old clone() method that did not use the new Cloner utility. + * The old clone() method that did not use the new Cloner utility. */ + @Deprecated public Spatial oldClone(boolean cloneMaterial) { - try { - Spatial clone = (Spatial) super.clone(); - if (worldBound != null) { - clone.worldBound = worldBound.clone(); - } - clone.worldLights = worldLights.clone(); - clone.localLights = localLights.clone(); - - // Set the new owner of the light lists - clone.localLights.setOwner(clone); - clone.worldLights.setOwner(clone); - - clone.worldOverrides = new SafeArrayList<>(MatParamOverride.class); - clone.localOverrides = new SafeArrayList<>(MatParamOverride.class); - - for (MatParamOverride override : localOverrides) { - clone.localOverrides.add((MatParamOverride) override.clone()); - } - - // No need to force cloned to update. - // This node already has the refresh flags - // set below so it will have to update anyway. - clone.worldTransform = worldTransform.clone(); - clone.localTransform = localTransform.clone(); - - if (clone instanceof Node) { - Node node = (Node) this; - Node nodeClone = (Node) clone; - nodeClone.children = new SafeArrayList(Spatial.class); - for (Spatial child : node.children) { - Spatial childClone = child.clone(cloneMaterial); - childClone.parent = nodeClone; - nodeClone.children.add(childClone); - } - } - - clone.parent = null; - clone.setBoundRefresh(); - clone.setTransformRefresh(); - clone.setLightListRefresh(); - clone.setMatParamOverrideRefresh(); - - clone.controls = new SafeArrayList(Control.class); - for (int i = 0; i < controls.size(); i++) { - Control newControl = controls.get(i).cloneForSpatial(clone); - newControl.setSpatial(clone); - clone.controls.add(newControl); - } - - if (userData != null) { - clone.userData = (HashMap) userData.clone(); - } - - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } + throw new UnsupportedOperationException(); } /** @@ -1442,9 +1388,6 @@ public Spatial oldClone(boolean cloneMaterial) { * Note that meshes of geometries are not cloned explicitly, they * are shared if static, or specially cloned if animated. * - * All controls will be cloned using the Control.cloneForSpatial method - * on the clone. - * * @see Mesh#cloneForAnim() */ @Override @@ -1879,4 +1822,4 @@ public boolean isVisible() { public void setVisible(boolean visible) { this.visible = visible; } -} \ No newline at end of file +} diff --git a/src/main/java/com/jme3/texture/Image.java b/src/main/java/com/jme3/texture/Image.java index 5817cb59..c1b3f344 100644 --- a/src/main/java/com/jme3/texture/Image.java +++ b/src/main/java/com/jme3/texture/Image.java @@ -258,6 +258,7 @@ public enum Format { * half-precision floating point red, green, and blue. * * Requires {@link Caps#FloatTexture}. + * May be supported for renderbuffers, but the OpenGL specification does not require it. */ RGB16F(48,true), @@ -272,6 +273,7 @@ public enum Format { * single-precision floating point red, green, and blue. * * Requires {@link Caps#FloatTexture}. + * May be supported for renderbuffers, but the OpenGL specification does not require it. */ RGB32F(96,true), @@ -301,30 +303,189 @@ public enum Format { */ ETC1(4, false, true, false), + /** + * 8 bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R8I(8), + /** + * 8 bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R8UI(8), + /** + * 16 bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R16I(16), + /** + * 16 bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R16UI(16), + /** + * 32 bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R32I(32), + /** + * 32 bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ R32UI(32), + + + /** + * 8 bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG8I(16), + /** + * 8 bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG8UI(16), + /** + * 16 bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG16I(32), + /** + * 16 bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG16UI(32), + /** + * 32 bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG32I(64), + /** + * 32 bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ RG32UI(64), + + /** + * 8 bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB8I(24), + /** + * 8 bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB8UI(24), + /** + * 16 bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB16I(48), + /** + * 16 bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB16UI(48), + /** + * 32 bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB32I(96), + /** + * 32 bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ RGB32UI(96), + + + /** + * 8 bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ RGBA8I(32), + /** + * 8 bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ RGBA8UI(32), + /** + * 16 bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ RGBA16I(64), + /** + * 16 bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ RGBA16UI(64), + /** + * 32 bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ RGBA32I(128), - RGBA32UI(128) + /** + * 32 bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA32UI(128), + + /** + * half-precision floating point red. + * + * Requires {@link Caps#FloatTexture}. + */ + R16F(16,true), + + /** + * single-precision floating point red. + * + * Requires {@link Caps#FloatTexture}. + */ + R32F(32,true), + + /** + * half-precision floating point red and green. + * + * Requires {@link Caps#FloatTexture}. + */ + RG16F(32,true), + + /** + * single-precision floating point red and green. + * + * Requires {@link Caps#FloatTexture}. + */ + RG32F(64,true), ; private int bpp; @@ -574,14 +735,14 @@ public Image(Format format, int width, int height, int depth, ArrayList data, @@ -630,13 +791,13 @@ public Image(Format format, int width, int height, ByteBuffer data, } /** - * @see {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], boolean)} + * @see {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace)} * @param format * @param width * @param height * @param data * @param mipMapSizes - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], boolean)} + * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace)} */ @Deprecated public Image(Format format, int width, int height, ByteBuffer data, @@ -664,13 +825,13 @@ public Image(Format format, int width, int height, int depth, ArrayList data) { @@ -698,12 +859,12 @@ public Image(Format format, int width, int height, ByteBuffer data, ColorSpace c /** - * @see {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, boolean)} + * @see {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace)} * @param format * @param width * @param height * @param data - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, boolean)} + * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace)} */ @Deprecated public Image(Format format, int width, int height, ByteBuffer data) { diff --git a/src/main/java/com/ss/editor/DevelopPluginStarter.java b/src/main/java/com/ss/builder/DevelopPluginStarter.java similarity index 95% rename from src/main/java/com/ss/editor/DevelopPluginStarter.java rename to src/main/java/com/ss/builder/DevelopPluginStarter.java index 94809b62..7af8e6c2 100644 --- a/src/main/java/com/ss/editor/DevelopPluginStarter.java +++ b/src/main/java/com/ss/builder/DevelopPluginStarter.java @@ -1,4 +1,4 @@ -package com.ss.editor; +package com.ss.builder; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/EditorThread.java b/src/main/java/com/ss/builder/EditorThread.java similarity index 89% rename from src/main/java/com/ss/editor/EditorThread.java rename to src/main/java/com/ss/builder/EditorThread.java index 631bcbe2..a0e5e69a 100644 --- a/src/main/java/com/ss/editor/EditorThread.java +++ b/src/main/java/com/ss/builder/EditorThread.java @@ -1,7 +1,7 @@ -package com.ss.editor; +package com.ss.builder; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/editor/FileExtensions.java b/src/main/java/com/ss/builder/FileExtensions.java similarity index 98% rename from src/main/java/com/ss/editor/FileExtensions.java rename to src/main/java/com/ss/builder/FileExtensions.java index 601d16bc..0e32df78 100644 --- a/src/main/java/com/ss/editor/FileExtensions.java +++ b/src/main/java/com/ss/builder/FileExtensions.java @@ -1,4 +1,4 @@ -package com.ss.editor; +package com.ss.builder; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/JfxApplication.java b/src/main/java/com/ss/builder/JfxApplication.java new file mode 100644 index 00000000..dc5c86b0 --- /dev/null +++ b/src/main/java/com/ss/builder/JfxApplication.java @@ -0,0 +1,541 @@ +package com.ss.builder; + +import static com.jme3.jfx.injfx.processor.FrameTransferSceneProcessor.TransferMode.ON_CHANGES; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_OPEN_GL; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_ANALYTICS_GOOGLE; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_OPEN_GL; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_STOP_RENDER_ON_LOST_FOCUS; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.jfx.injfx.JmeToJfxIntegrator; +import com.jme3.jfx.injfx.processor.FrameTransferSceneProcessor; +import com.jme3.util.LWJGLBufferAllocator; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.CommandLineConfig; +import com.ss.builder.config.Config; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.executor.impl.JmeThreadExecutor; +import com.ss.builder.fx.builder.EditorFxSceneBuilder; +import com.ss.builder.fx.css.CssRegistry; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.fx.scene.EditorFxScene; +import com.ss.builder.manager.*; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import com.ss.builder.task.CheckNewVersionTask; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.OpenGLVersion; +import com.ss.builder.util.TimeTracker; +import com.ss.builder.util.svg.SvgImageLoaderFactory; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerLevel; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.logging.impl.FolderFileListener; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.ArrayUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.array.ConcurrentArray; +import com.ss.rlib.fx.util.ObservableUtils; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.Configuration; + +import javax.imageio.ImageIO; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; + +/** + * The starter of the JavaFX application. + * + * @author JavaSaBr + */ +public class JfxApplication extends Application { + + private static final Logger LOGGER = LoggerManager.getLogger(JfxApplication.class); + + @Nullable + private static JfxApplication instance; + + /** + * It's an internal method. + * + * @see EditorUtils + */ + @Deprecated + @FromAnyThread + public static @NotNull JfxApplication getInstance() { + return notNull(instance); + } + + /** + * The start application method. + */ + public static void main(@NotNull String[] args) { + + TimeTracker.getStartupTracker() + .start(); + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .start(); + + configureLogger(); + + // need to disable to work on macos + Configuration.GLFW_CHECK_THREAD0.set(false); + // use jemalloc + Configuration.MEMORY_ALLOCATOR.set("jemalloc"); + + // JavaFX + System.setProperty("prism.lcdtext", "false"); + //System.setProperty("prism.text", "t2k"); + + var editorConfig = EditorConfig.getInstance(); + var openGLVersion = editorConfig.getEnum(PREF_OPEN_GL, PREF_DEFAULT_OPEN_GL); + + // set a render if it isn't override + if(System.getProperty("jfx.background.render") == null) { + System.setProperty("jfx.background.render", openGLVersion.getRender()); + } + + System.setProperty(LWJGLBufferAllocator.PROPERTY_CONCURRENT_BUFFER_ALLOCATOR, "true"); + + CommandLineConfig.args(args); + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .finishAndStart(() -> "initialized configuration"); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(JfxApplication::createSceneProcessor) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .add(FxContextCreatedEvent.EVENT_TYPE) + .add(ImageSystemInitializedEvent.EVENT_TYPE) + .add(AllPluginsExtensionsRegisteredEvent.EVENT_TYPE) + .buildAndRegister(); + + InitializeManager.register(ExecutorManager.class); + InitializeManager.register(FxEventManager.class); + InitializeManager.register(ClasspathManager.class); + InitializeManager.register(ResourceManager.class); + InitializeManager.register(JavaFxImageManager.class); + InitializeManager.register(FileIconManager.class); + InitializeManager.register(WorkspaceManager.class); + InitializeManager.register(CssRegistry.class); + InitializeManager.register(RenderFilterRegistry.class); + InitializeManager.register(PluginManager.class); + InitializeManager.register(RemoteControlManager.class); + InitializeManager.initialize(); + + new EditorThread(new ThreadGroup("JavaFX"), + JfxApplication::start, "JavaFX Launch").start(); + new EditorThread(new ThreadGroup("LWJGL"), + JfxApplication::startJmeApplication, "LWJGL Render").start(); + + AsyncEventManager.getInstance() + .notify(new ManagersInitializedEvent()); + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .finish(() -> "initializing of all managers"); + } + + @FxThread + private static void configureLogger() { + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .start(); + + // disable the standard logger + if (!Config.DEV_DEBUG) { + java.util.logging.Logger.getLogger("").setLevel(Level.WARNING); + } else { + java.util.logging.Logger.getLogger("").setLevel(Level.ALL); + } + + // configure our logger + LoggerLevel.DEBUG.setEnabled(Config.DEV_DEBUG); + LoggerLevel.INFO.setEnabled(true); + LoggerLevel.ERROR.setEnabled(true); + LoggerLevel.WARNING.setEnabled(true); + + LoggerManager.getLogger(AsyncEventManager.class) + .setEnabled(LoggerLevel.DEBUG, Config.DEV_DEBUG_ASYNC_EVENT_MANAGER); + + var logFolder = Config.getFolderForLog(); + + if (!Files.exists(logFolder)) { + FileUtils.createDirectories(logFolder); + } + + if (!LoggerLevel.DEBUG.isEnabled()) { + LoggerManager.addListener(new FolderFileListener(logFolder)); + } + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .finish(() -> "configuring of the logger"); + } + + /** + * Start the new jME application. + */ + @JmeThread + private static void startJmeApplication() { + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .start(); + + var application = JmeApplication.getInstance(); + application.start(); + + var context = application.getContext(); + var renderer = context.getRenderer(); + + if (renderer == null) { + var editorConfig = EditorConfig.getInstance(); + editorConfig.set(PREF_OPEN_GL, OpenGLVersion.GL_20); + editorConfig.save(); + } + } + + /** + * Create a new focus listener. + * + * @return the new focus listener. + */ + @FxThread + private static @NotNull ChangeListener makeFocusedListener() { + return (observable, oldValue, newValue) -> { + + var jmeApplication = JmeApplication.getInstance(); + var stage = EditorUtils.getFxStage(); + + if (newValue || stage.isFocused()) { + jmeApplication.setPaused(false); + return; + } + + var editorConfig = EditorConfig.getInstance(); + + if (!editorConfig.getBoolean(PREF_STOP_RENDER_ON_LOST_FOCUS, PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS)) { + jmeApplication.setPaused(false); + return; + } + + var application = JfxApplication.getInstance(); + var window = ArrayUtils.getInReadLock(application.openedWindows, + windows -> windows.findAny(Window::isFocused)); + + jmeApplication.setPaused(window == null); + }; + } + + @BackgroundThread + private static void createSceneProcessor() { + ExecutorManager.getInstance() + .addFxTask(JfxApplication::createSceneProcessorImpl); + } + + @FxThread + private static void createSceneProcessorImpl() { + + var jfxApplication = getInstance(); + var jmeApplication = JmeApplication.getInstance(); + + var scene = jfxApplication.getScene(); + var stage = jfxApplication.getStage(); + + var sceneProcessor = JmeToJfxIntegrator.bind(jmeApplication, scene.getCanvas(), jmeApplication.getViewPort()); + sceneProcessor.setEnabled(false); + sceneProcessor.setTransferMode(ON_CHANGES); + + jfxApplication.sceneProcessor = sceneProcessor; + + stage.focusedProperty() + .addListener(makeFocusedListener()); + + ExecutorManager.getInstance() + .addBackgroundTask(scene::notifyFinishBuild); + } + + /** + * Start. + */ + @FromAnyThread + public static void start() { + launch(); + } + + /** + * The list of opened windows. + */ + @NotNull + private final ConcurrentArray openedWindows; + + /** + * The JavaFX scene. + */ + @Nullable + private volatile EditorFxScene scene; + + /** + * The scene processor. + */ + @Nullable + private volatile FrameTransferSceneProcessor sceneProcessor; + + /** + * The stage. + */ + @Nullable + private Stage stage; + + public JfxApplication() { + EditorUtils.setJfxApplication(this); + this.openedWindows = ArrayFactory.newConcurrentStampedLockArray(Window.class); + } + + /** + * Request focus of this window. + */ + public void requestFocus() { + notNull(stage).requestFocus(); + } + + /** + * Add the new opened window. + * + * @param window the new opened window. + */ + @FxThread + public void addWindow(@NotNull Window window) { + window.focusedProperty().addListener(makeFocusedListener()); + ArrayUtils.runInWriteLock(openedWindows, window, Collection::add); + } + + /** + * Remove the opened window. + * + * @param window the opened window. + */ + @FxThread + public void removeWindow(@NotNull Window window) { + ArrayUtils.runInWriteLock(openedWindows, window, Array::slowRemove); + } + + /** + * Gets the last opened window. + * + * @return the last opened window. + */ + @FxThread + public @NotNull Window getLastWindow() { + return notNull(ArrayUtils.getInReadLock(openedWindows, Array::last)); + } + + @Override + @FxThread + public void start(@NotNull Stage stage) { + JfxApplication.instance = this; + this.stage = stage; + + addWindow(stage); + try { + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .start(); + + var icons = stage.getIcons(); + icons.add(new Image("/ui/icons/app/256x256.png")); + icons.add(new Image("/ui/icons/app/64x64.png")); + icons.add(new Image("/ui/icons/app/48x48.png")); + icons.add(new Image("/ui/icons/app/32x32.png")); + icons.add(new Image("/ui/icons/app/24x24.png")); + icons.add(new Image("/ui/icons/app/16x16.png")); + + var config = EditorConfig.getInstance(); + + stage.initStyle(StageStyle.DECORATED); + stage.setMinHeight(600); + stage.setMinWidth(800); + stage.setWidth(config.getScreenWidth()); + stage.setHeight(config.getScreenHeight()); + stage.setMaximized(config.isMaximized()); + stage.setTitle(Config.TITLE); + stage.show(); + + if (!stage.isMaximized()) { + stage.centerOnScreen(); + } + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .finishAndStart(() -> "initialized of the FX stage"); + + ObservableUtils.onChangeIf(stage.widthProperty(), number -> !stage.isMaximized(), + number -> config.setScreenWidth(number.intValue())); + ObservableUtils.onChangeIf(stage.heightProperty(), number -> !stage.isMaximized(), + number -> config.setScreenHeight(number.intValue())); + + ObservableUtils.onChange(stage.maximizedProperty(), config::setMaximized); + + AsyncEventManager.SingleAsyncEventHandlerBuilder.of(FxSceneAttachedEvent.EVENT_TYPE) + .add(this::initializeImageSystem) + .buildAndRegister(); + + ExecutorManager.getInstance() + .addBackgroundTask(this::buildScene); + + } catch (Throwable e) { + LOGGER.error(this, e); + throw e; + } + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .finish(() -> "initializing of jFX application"); + TimeTracker.getStartupTracker() + .finish(() -> "showing of the main window editor"); + } + + /** + * Initialize the image system. + */ + @BackgroundThread + private void initializeImageSystem() { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + + SvgImageLoaderFactory.install(); + try { + ImageIO.read(getClass().getResourceAsStream("/ui/icons/svg/picture.svg")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + LOGGER.info("image system is initialized."); + + AsyncEventManager.getInstance() + .notify(new ImageSystemInitializedEvent()); + }); + } + + @Override + @FxThread + public void stop() throws Exception { + super.stop(); + onExit(); + } + + /** + * On exit. + */ + @FxThread + protected void onExit() { + + GAnalytics.forceSendEvent(GAEvent.Category.APPLICATION, + GAEvent.Action.APPLICATION_CLOSED, GAEvent.Label.THE_EDITOR_APP_WAS_CLOSED); + + var config = EditorConfig.getInstance(); + config.save(); + + var waiter = new CountDownLatch(1); + + var executor = JmeThreadExecutor.getInstance(); + executor.addToExecute(() -> { + JmeApplication.getInstance().destroy(); + waiter.countDown(); + }); + + GAnalytics.waitForSend(); + Utils.run(waiter::await); + } + + /** + * Build the scene. + */ + @BackgroundThread + private void buildScene() { + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_5) + .start(); + + this.scene = EditorFxSceneBuilder.build(notNull(stage)); + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_5) + .finishAndStart(() -> "creating of the FX scene"); + + AsyncEventManager.getInstance() + .notify(new FxSceneCreatedEvent()); + + GAnalytics.forceSendEvent(GAEvent.Category.APPLICATION, + GAEvent.Action.APPLICATION_LAUNCHED, GAEvent.Label.THE_EDITOR_APP_WAS_LAUNCHED); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addBackgroundTask(new CheckNewVersionTask()); + + var editorConfig = EditorConfig.getInstance(); + if (editorConfig.isAnalyticsQuestion()) { + return; + } + + editorConfig.set(PREF_ANALYTICS_GOOGLE, false); + editorConfig.save(); + + Platform.runLater(() -> { + + var stage = notNull(getStage()); + var confirmDialog = new ConfirmDialog(result -> { + + editorConfig.setAnalyticsQuestion(true); + editorConfig.set(PREF_ANALYTICS_GOOGLE, Boolean.TRUE.equals(result)); + editorConfig.save(); + + }, Messages.ANALYTICS_CONFIRM_DIALOG_MESSAGE); + + confirmDialog.show(stage); + }); + } + + /** + * Get the current JavaFX scene. + * + * @return the JavaFX scene. + */ + @FromAnyThread + public @NotNull EditorFxScene getScene() { + return notNull(scene, "Scene can't be null."); + } + + /** + * Get the current stage of JavaFX. + * + * @return the current stage. + */ + @FromAnyThread + public @NotNull Stage getStage() { + return notNull(stage); + } + + /** + * Get the current scene processor of this application. + * + * @return the scene processor. + */ + @FromAnyThread + public @NotNull FrameTransferSceneProcessor getSceneProcessor() { + return notNull(sceneProcessor, "Scene processor can't be null."); + } +} diff --git a/src/main/java/com/ss/editor/JmeApplication.java b/src/main/java/com/ss/builder/JmeApplication.java similarity index 87% rename from src/main/java/com/ss/editor/JmeApplication.java rename to src/main/java/com/ss/builder/JmeApplication.java index 641118a1..134eab25 100644 --- a/src/main/java/com/ss/editor/JmeApplication.java +++ b/src/main/java/com/ss/builder/JmeApplication.java @@ -1,8 +1,8 @@ -package com.ss.editor; +package com.ss.builder; import static com.jme3.environment.LightProbeFactory.makeProbe; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.*; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.*; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.*; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.app.DebugKeysAppState; import com.jme3.asset.AssetNotFoundException; @@ -18,7 +18,6 @@ import com.jme3.light.LightProbe; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; -import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.FXAAFilter; @@ -27,22 +26,24 @@ import com.jme3.renderer.RendererException; import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.asset.locator.FileSystemAssetLocator; -import com.ss.editor.asset.locator.FolderAssetLocator; -import com.ss.editor.config.Config; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.executor.impl.JmeThreadExecutor; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.Config; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.executor.impl.JmeThreadExecutor; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.JmeContextCreatedEvent; +import com.ss.builder.fx.event.impl.WindowChangeFocusEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.jme.asset.locator.FileSystemAssetLocator; +import com.ss.builder.jme.asset.locator.FolderAssetLocator; +import com.ss.builder.jme.filter.EditorFXAAFilter; +import com.ss.builder.manager.AsyncEventManager; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.TimeTracker; import com.ss.editor.extension.loader.SceneLoader; -import com.ss.editor.filter.EditorFxaaFilter; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.InitializationManager; -import com.ss.editor.manager.WorkspaceManager; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.WindowChangeFocusEvent; -import com.ss.editor.util.EditorUtil; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.util.os.OperatingSystem; @@ -64,7 +65,6 @@ public class JmeApplication extends JmeToJfxApplication { /** * The empty job adapter for handling creating {@link LightProbe}. */ - @NotNull private static final JobProgressAdapter EMPTY_JOB_ADAPTER = new JobProgressAdapter<>() { public void done(@NotNull LightProbe result) { } @@ -76,7 +76,7 @@ public void done(@NotNull LightProbe result) { /** * It's an internal method. * - * @see EditorUtil + * @see EditorUtils */ @Deprecated @FromAnyThread @@ -84,36 +84,6 @@ public void done(@NotNull LightProbe result) { return JME_APPLICATION; } - /** - * Prepare to start editor. - * - * @return the editor - */ - @JmeThread - static @NotNull JmeApplication prepareToStart() { - - if (Config.DEV_DEBUG) { - System.err.println("config was loaded."); - } - - try { - - var config = EditorConfig.getInstance(); - var settings = config.getSettings(); - - JME_APPLICATION.setSettings(settings); - JME_APPLICATION.setShowSettings(false); - JME_APPLICATION.setDisplayStatView(false); - JME_APPLICATION.setDisplayFps(false); - - } catch (Exception e) { - LOGGER.warning(e); - throw new RuntimeException(e); - } - - return JME_APPLICATION; - } - /** * The main synchronizer of this application. */ @@ -181,9 +151,18 @@ public void done(@NotNull LightProbe result) { private Material defaultMaterial; private JmeApplication() { - EditorUtil.setJmeApplication(this); + EditorUtils.setJmeApplication(this); + this.lock = new StampedLock(); this.previewNode = new Node("Preview Node"); + + var config = EditorConfig.getInstance(); + var settings = config.getSettings(); + + setDisplayFps(false); + setSettings(settings); + setShowSettings(false); + setDisplayStatView(false); } /** @@ -223,6 +202,11 @@ public void destroy() { return super.getCamera(); } + @Override + public void initialize() { + super.initialize(); + } + @Override @JmeThread public void simpleInitApp() { @@ -249,7 +233,9 @@ public void simpleInitApp() { var audioRenderer = getAudioRenderer(); audioRenderer.setEnvironment(new Environment(Environment.Garage)); - viewPort.setBackgroundColor(new ColorRGBA(50 / 255F, 50 / 255F, 50 / 255F, 1F)); + var theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); + + viewPort.setBackgroundColor(UiUtils.from(theme.getBackgroundColor())); cam.setFrustumPerspective(55, (float) cam.getWidth() / cam.getHeight(), 1f, Integer.MAX_VALUE); defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); @@ -265,14 +251,12 @@ public void simpleInitApp() { var guiNode = getGuiNode(); guiNode.detachAllChildren(); - ExecutorManager.getInstance(); - flyCam.setDragToRotate(true); flyCam.setEnabled(false); var postProcessor = getPostProcessor(); - fxaaFilter = new EditorFxaaFilter(); + fxaaFilter = new EditorFXAAFilter(); fxaaFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER)); fxaaFilter.setSubPixelShift(1.0f / 4.0f); fxaaFilter.setVxOffset(0.0f); @@ -298,10 +282,13 @@ public void simpleInitApp() { createLightProbes(); stateManager.detach(stateManager.getState(DebugKeysAppState.class)); - var initializationManager = InitializationManager.getInstance(); - initializationManager.onAfterCreateJmeContext(); + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_2) + .finishAndStart(() -> "initializing of jME application"); + + LOGGER.info("initialized."); - new EditorThread(new ThreadGroup("JavaFX"), JfxApplication::start, "JavaFX Launch").start(); + AsyncEventManager.getInstance() + .notify(new JmeContextCreatedEvent()); } /** diff --git a/src/main/java/com/ss/editor/Messages.java b/src/main/java/com/ss/builder/Messages.java similarity index 99% rename from src/main/java/com/ss/editor/Messages.java rename to src/main/java/com/ss/builder/Messages.java index 22305037..40c0daf7 100644 --- a/src/main/java/com/ss/editor/Messages.java +++ b/src/main/java/com/ss/builder/Messages.java @@ -1,4 +1,4 @@ -package com.ss.editor; +package com.ss.builder; import static java.util.ResourceBundle.getBundle; import com.ss.rlib.common.util.PropertyLoader; @@ -168,6 +168,7 @@ public class Messages { public static final String MODEL_FILE_EDITOR_NODE_SPOT_LIGHT; public static final String MODEL_FILE_EDITOR_NODE_LIGHT_PROBE; public static final String MODEL_FILE_EDITOR_NODE_ANIM_CONTROL; + public static final String MODEL_FILE_EDITOR_NODE_ANIM_COMPOSER; public static final String MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCERS; public static final String MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_EMPTY; public static final String MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_DEFAULT; @@ -859,6 +860,7 @@ public class Messages { MODEL_FILE_EDITOR_NODE_SPOT_LIGHT = bundle.getString("ModelFileEditorNodeSpotLight"); MODEL_FILE_EDITOR_NODE_LIGHT_PROBE = bundle.getString("ModelFileEditorNodeLightProbe"); MODEL_FILE_EDITOR_NODE_ANIM_CONTROL = bundle.getString("ModelFileEditorNodeAnimControl"); + MODEL_FILE_EDITOR_NODE_ANIM_COMPOSER = bundle.getString("ModelFileEditorNodeAnimComposer"); MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCERS = bundle.getString("ModelFileEditorNodeParticleEmitterInfluencers"); MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_EMPTY = bundle.getString("ModelFileEditorNodeParticleEmitterInfluencerEmpty"); MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_DEFAULT = bundle.getString("ModelFileEditorNodeParticleEmitterInfluencerDefault"); diff --git a/src/main/java/com/ss/editor/analytics/google/GAEvent.java b/src/main/java/com/ss/builder/analytics/google/GAEvent.java similarity index 98% rename from src/main/java/com/ss/editor/analytics/google/GAEvent.java rename to src/main/java/com/ss/builder/analytics/google/GAEvent.java index 1158b184..36f14973 100644 --- a/src/main/java/com/ss/editor/analytics/google/GAEvent.java +++ b/src/main/java/com/ss/builder/analytics/google/GAEvent.java @@ -1,4 +1,4 @@ -package com.ss.editor.analytics.google; +package com.ss.builder.analytics.google; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/analytics/google/GAnalytics.java b/src/main/java/com/ss/builder/analytics/google/GAnalytics.java similarity index 96% rename from src/main/java/com/ss/editor/analytics/google/GAnalytics.java rename to src/main/java/com/ss/builder/analytics/google/GAnalytics.java index 70c124f9..06d7325d 100644 --- a/src/main/java/com/ss/editor/analytics/google/GAnalytics.java +++ b/src/main/java/com/ss/builder/analytics/google/GAnalytics.java @@ -1,13 +1,14 @@ -package com.ss.editor.analytics.google; +package com.ss.builder.analytics.google; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_ANALYTICS_GOOGLE; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_ANALYTICS_GOOGLE; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_ANALYTICS_GOOGLE; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_ANALYTICS_GOOGLE; import static com.ss.rlib.common.util.StringUtils.isEmpty; import static org.apache.http.impl.client.HttpClients.createMinimal; -import com.ss.editor.EditorThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.Config; -import com.ss.editor.config.EditorConfig; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.EditorThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.Config; +import com.ss.builder.config.EditorConfig; import com.ss.rlib.common.concurrent.util.ConcurrentUtils; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; @@ -270,7 +271,7 @@ private static void send(@NotNull final Map parameters) { */ private static void doSend(@NotNull final Map parameters) { - final OperatingSystem operatingSystem = Config.OPERATING_SYSTEM; + final OperatingSystem operatingSystem = Config.getOperatingSystem(); final String distribution = operatingSystem.getDistribution(); final String os = StringUtils.isEmpty(distribution) ? operatingSystem.getName() + " " + operatingSystem.getVersion() : distribution; diff --git a/src/main/java/com/ss/editor/analytics/google/HitType.java b/src/main/java/com/ss/builder/analytics/google/HitType.java similarity index 95% rename from src/main/java/com/ss/editor/analytics/google/HitType.java rename to src/main/java/com/ss/builder/analytics/google/HitType.java index c1fd5f90..1828380c 100644 --- a/src/main/java/com/ss/editor/analytics/google/HitType.java +++ b/src/main/java/com/ss/builder/analytics/google/HitType.java @@ -1,4 +1,4 @@ -package com.ss.editor.analytics.google; +package com.ss.builder.analytics.google; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/annotation/BackgroundThread.java b/src/main/java/com/ss/builder/annotation/BackgroundThread.java similarity index 87% rename from src/main/java/com/ss/editor/annotation/BackgroundThread.java rename to src/main/java/com/ss/builder/annotation/BackgroundThread.java index 1858a6e9..1ff037ba 100644 --- a/src/main/java/com/ss/editor/annotation/BackgroundThread.java +++ b/src/main/java/com/ss/builder/annotation/BackgroundThread.java @@ -1,4 +1,4 @@ -package com.ss.editor.annotation; +package com.ss.builder.annotation; import java.lang.annotation.*; diff --git a/src/main/java/com/ss/editor/annotation/FromAnyThread.java b/src/main/java/com/ss/builder/annotation/FromAnyThread.java similarity index 92% rename from src/main/java/com/ss/editor/annotation/FromAnyThread.java rename to src/main/java/com/ss/builder/annotation/FromAnyThread.java index 2083a579..999acc11 100644 --- a/src/main/java/com/ss/editor/annotation/FromAnyThread.java +++ b/src/main/java/com/ss/builder/annotation/FromAnyThread.java @@ -1,4 +1,4 @@ -package com.ss.editor.annotation; +package com.ss.builder.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/src/main/java/com/ss/editor/annotation/FxThread.java b/src/main/java/com/ss/builder/annotation/FxThread.java similarity index 92% rename from src/main/java/com/ss/editor/annotation/FxThread.java rename to src/main/java/com/ss/builder/annotation/FxThread.java index e0a2064f..41e35d79 100644 --- a/src/main/java/com/ss/editor/annotation/FxThread.java +++ b/src/main/java/com/ss/builder/annotation/FxThread.java @@ -1,4 +1,4 @@ -package com.ss.editor.annotation; +package com.ss.builder.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/src/main/java/com/ss/editor/annotation/JmeThread.java b/src/main/java/com/ss/builder/annotation/JmeThread.java similarity index 92% rename from src/main/java/com/ss/editor/annotation/JmeThread.java rename to src/main/java/com/ss/builder/annotation/JmeThread.java index 1cd13f5b..16a7cc7a 100644 --- a/src/main/java/com/ss/editor/annotation/JmeThread.java +++ b/src/main/java/com/ss/builder/annotation/JmeThread.java @@ -1,4 +1,4 @@ -package com.ss.editor.annotation; +package com.ss.builder.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/src/main/java/com/ss/editor/config/CommandLineConfig.java b/src/main/java/com/ss/builder/config/CommandLineConfig.java similarity index 81% rename from src/main/java/com/ss/editor/config/CommandLineConfig.java rename to src/main/java/com/ss/builder/config/CommandLineConfig.java index c4b3358f..d41d669b 100644 --- a/src/main/java/com/ss/editor/config/CommandLineConfig.java +++ b/src/main/java/com/ss/builder/config/CommandLineConfig.java @@ -1,9 +1,8 @@ -package com.ss.editor.config; +package com.ss.builder.config; import org.jetbrains.annotations.NotNull; import java.nio.file.Paths; -import java.util.Map; /** * Parser the configuration from command-line arguments. @@ -12,35 +11,31 @@ */ public class CommandLineConfig { - @NotNull public static final String PREF_SERVER_API_PORT = "Server.api.port"; - - @NotNull public static final String PREF_SERVER_API_VERSION = "Server.api.version"; - - @NotNull public static final String PREF_EDITOR_ASSET_FOLDER = "Editor.assetFolder"; /** * @param args the args */ - public static void args(final String[] args) { + public static void args(@NotNull String[] args) { - final EditorConfig editorConfig = EditorConfig.getInstance(); + var editorConfig = EditorConfig.getInstance(); - for (final String arg : args) { + for (var arg : args) { if (!arg.contains("=")) { continue; } - final String[] values = arg.split("="); + var values = arg.split("="); + if (values.length != 2) { continue; } - final String name = values[0]; - final String value = values[1]; + var name = values[0]; + var value = values[1]; if ("Dev.debug".equals(name)) { Config.DEV_DEBUG = Boolean.parseBoolean(value); @@ -63,10 +58,10 @@ public static void args(final String[] args) { } } - final Map env = System.getenv(); + var env = System.getenv(); if (env.containsKey(PREF_SERVER_API_VERSION)) { - final int version = Integer.parseInt(env.get(PREF_SERVER_API_VERSION)); + var version = Integer.parseInt(env.get(PREF_SERVER_API_VERSION)); if (version == Config.SERVER_API_VERSION) { System.exit(100); } else { @@ -77,6 +72,7 @@ public static void args(final String[] args) { if (env.containsKey(PREF_SERVER_API_PORT)) { Config.REMOTE_CONTROL_PORT = Integer.parseInt(env.get(PREF_SERVER_API_PORT)); } + if (env.containsKey(PREF_EDITOR_ASSET_FOLDER)) { editorConfig.setCurrentAsset(Paths.get(env.get(PREF_EDITOR_ASSET_FOLDER))); } diff --git a/src/main/java/com/ss/builder/config/Config.java b/src/main/java/com/ss/builder/config/Config.java new file mode 100644 index 00000000..9222583b --- /dev/null +++ b/src/main/java/com/ss/builder/config/Config.java @@ -0,0 +1,221 @@ +package com.ss.builder.config; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.TimeTracker; +import com.ss.rlib.common.plugin.Version; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.os.OperatingSystem; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The configuration of this application. + * + * @author JavaSaBr + */ +public final class Config { + + /** + * The path to config file in classpath. + */ + private static final String CONFIG_RESOURCE_PATH = "/app-config.json"; + + /** + * The name of editor's folder in user home folder. + */ + private static final String EDITOR_FOLDER_IN_USER_HOME = ".jmonkeybuilder"; + + /** + * The editor's title. + */ + public static final String TITLE = "jMonkeyBuilder"; + + /** + * The editor's version. + */ + public static final Version APP_VERSION = new Version("1.9.0"); + + /** + * The string version. + */ + public static final String STRING_VERSION = APP_VERSION.toString(); + + /** + * The server API version. + */ + public static final int SERVER_API_VERSION = 1; + + /** + * The path to application folder. + */ + public static final String PROJECT_PATH; + + /** + * The graphics adapter. + */ + private static GraphicsDevice graphicsDevice; + + /** + * The operation system. + */ + private static OperatingSystem operatingSystem; + + /** + * The remote control port. + */ + public static int REMOTE_CONTROL_PORT = -1; + + /** + * The flag to enable debug mode. + */ + public static boolean DEV_DEBUG; + + /** + * The flag to enable camera debug mode. + */ + public static boolean DEV_CAMERA_DEBUG; + + /** + * The flag to enable camera checks debug mode. + */ + public static boolean DEV_CAMERA_CHECKS_DEBUG; + + /** + * The flag to enable transformations debug mode. + */ + public static boolean DEV_TRANSFORMS_DEBUG; + + /** + * The flag to enable JavaFX debug mode. + */ + public static boolean DEV_DEBUG_JFX; + + /** + * The flag to enable JavaFX mouse input debug mode. + */ + public static boolean DEV_DEBUG_JFX_MOUSE_INPUT; + + /** + * The flag to enable javaFX key input debug mode. + */ + public static boolean DEV_DEBUG_JFX_KEY_INPUT; + + /** + * The flag to enable startup debug mode. + */ + public static boolean DEV_DEBUG_STARTUP; + + /** + * The flag to enable debug of async event manager. + */ + public static boolean DEV_DEBUG_ASYNC_EVENT_MANAGER; + + /** + * The flag to enable PBR render. + */ + public static boolean ENABLE_PBR; + + /** + * The flag to enable 3D part of this editor. + */ + public static boolean ENABLE_3D; + + static { + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .start(); + + var vars = VarTable.newInstance(); + + try (var reader = new InputStreamReader(EditorUtils.requireInputStream(CONFIG_RESOURCE_PATH))) { + + var object = (JsonObject) Json.parse(reader); + object.forEach(member -> vars.set(member.getName(), member.getValue().toString())); + + } catch (IOException e) { + throw new RuntimeException(e); + } + + DEV_DEBUG = vars.getBoolean("Dev.debug", false); + DEV_CAMERA_DEBUG = vars.getBoolean("Dev.cameraDebug", false); + DEV_CAMERA_CHECKS_DEBUG = vars.getBoolean("Dev.cameraChecksDebug", false); + DEV_TRANSFORMS_DEBUG = vars.getBoolean("Dev.transformsDebug", false); + DEV_DEBUG_JFX_MOUSE_INPUT = vars.getBoolean("Dev.jfxMouseInput", false); + DEV_DEBUG_JFX_KEY_INPUT = vars.getBoolean("Dev.jfxKeyInput", false); + DEV_DEBUG_JFX = vars.getBoolean("Dev.debugJFX", false); + DEV_DEBUG_STARTUP = vars.getBoolean("Dev.debugStartup", false); + DEV_DEBUG_ASYNC_EVENT_MANAGER = vars.getBoolean("Dev.debugAsyncEventManager", false); + ENABLE_PBR = vars.getBoolean("Graphics.enablePBR", true); + ENABLE_3D = vars.getBoolean("Graphics.enable3D", true); + + PROJECT_PATH = Utils.getRootFolderFromClass(JmeApplication.class) + .toString(); + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .finish(() -> "loading of the root config"); + + } + + /** + * Get a folder to store log files. + * + * @return the path to a folder to store log files. + */ + @FromAnyThread + public static @NotNull Path getFolderForLog() { + return getAppFolderInUserHome().resolve("log"); + } + + /** + * Get a path to the folder to store data in a user home. + * + * @return the path to the folder to store data in a user home. + */ + @FromAnyThread + public static @NotNull Path getAppFolderInUserHome() { + var userHome = System.getProperty("user.home"); + return Paths.get(userHome, EDITOR_FOLDER_IN_USER_HOME); + } + + /** + * Get the information about OS. + * + * @return the information about OS. + */ + @FromAnyThread + public synchronized static @NotNull OperatingSystem getOperatingSystem() { + + if (operatingSystem == null) { + operatingSystem = new OperatingSystem(); + } + + return operatingSystem; + } + + /** + * Get the information about used graphics device. + * + * @return the information about used graphics device. + */ + @FromAnyThread + public synchronized static GraphicsDevice getGraphicsDevice() { + + + if (graphicsDevice == null) { + var graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); + graphicsDevice = graphicsEnvironment.getDefaultScreenDevice(); + } + + return graphicsDevice; + } +} diff --git a/src/main/java/com/ss/builder/config/DefaultSettingsProvider.java b/src/main/java/com/ss/builder/config/DefaultSettingsProvider.java new file mode 100644 index 00000000..e4c9bb0a --- /dev/null +++ b/src/main/java/com/ss/builder/config/DefaultSettingsProvider.java @@ -0,0 +1,180 @@ +package com.ss.builder.config; + +import static com.ss.builder.config.DefaultSettingsProvider.Categories.*; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.*; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.*; +import static com.ss.editor.extension.property.EditablePropertyType.*; +import static com.ss.rlib.common.util.array.ArrayFactory.asArray; +import com.jme3.math.Vector3f; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssColorTheme; +import com.ss.builder.plugin.api.settings.SettingsCategory; +import com.ss.builder.plugin.api.settings.SettingsPropertyDefinition; +import com.ss.builder.plugin.api.settings.SettingsProvider; +import com.ss.builder.util.OpenGLVersion; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * The default implementation of {@link SettingsProvider} + * + * @author JavaSaBr + */ +public class DefaultSettingsProvider implements SettingsProvider { + + public interface Categories { + @NotNull SettingsCategory GRAPHICS = new SettingsCategory("core.graphics", Messages.SETTINGS_CATEGORY_GRAPHICS, 0); + @NotNull SettingsCategory EDITOR = new SettingsCategory("core.editor", Messages.SETTINGS_CATEGORY_EDITOR, 1); + @NotNull SettingsCategory OTHER = new SettingsCategory("core.other", Messages.SETTINGS_CATEGORY_OTHER, 2); + } + + public interface Preferences { + + @NotNull String PREF_OPEN_GL = "core.graphics.openGL.version"; + @NotNull String PREF_ANISOTROPY = "core.graphics.anisotropy"; + @NotNull String PREF_GAMMA_CORRECTION = "core.graphics.gammaCorrection"; + @NotNull String PREF_FRAME_RATE = "core.graphics.frame.rate"; + @NotNull String PREF_CAMERA_ANGLE = "core.graphics.camera.angle"; + @NotNull String PREF_FILTER_FXAA = "core.graphics.filter.fxaa"; + @NotNull String PREF_FILTER_TONEMAP = "core.graphics.filter.toneMap"; + @NotNull String PREF_FILTER_TONEMAP_WHITE_POINT = "core.graphics.filter.toneMap.whitePoint"; + @NotNull String PREF_STOP_RENDER_ON_LOST_FOCUS = "core.graphics.render.stopOnLostFocus"; + + @NotNull String PREF_USER_LIBRARY_FOLDER = "core.classpath.library.folder"; + @NotNull String PREF_USER_CLASSES_FOLDER = "core.classpath.classes.folder"; + + @NotNull String PREF_UI_THEME = "core.ui.theme"; + @NotNull String PREF_ANALYTICS_GOOGLE = "core.other.analytics.google"; + @NotNull String PREF_NATIVE_FILE_CHOOSER = "core.other.native.file.chooser"; + + @NotNull String PREF_FAST_SKY_FOLDER = "core.editor.fast.sky.folder"; + @NotNull String PREF_TANGENT_GENERATION = "core.editor.tangent.generation"; + @NotNull String PREF_FLIPPED_TEXTURES = "core.editor.texture.flipped"; + @NotNull String PREF_CAMERA_LAMP = "core.editor.camera.lamp"; + } + + public interface Defaults { + + @NotNull OpenGLVersion PREF_DEFAULT_OPEN_GL = OpenGLVersion.GL_33; + @NotNull CssColorTheme PREF_DEFAULT_THEME = CssColorTheme.DARK; + + @NotNull Vector3f PREF_DEFAULT_TONEMAP_WHITE_POINT = new Vector3f(11, 11, 11); + + int PREF_DEFAULT_ANISOTROPY = 16; + int PREF_DEFAULT_FRAME_RATE = 60; + int PREF_DEFAULT_CAMERA_ANGLE = 75; + + boolean PREF_DEFAULT_TONEMAP_FILTER = true; + boolean PREF_DEFAULT_GAMMA_CORRECTION = true; + boolean PREF_DEFAULT_NATIVE_FILE_CHOOSER = false; + boolean PREF_DEFAULT_FXAA_FILTER = true; + boolean PREF_DEFAULT_CAMERA_LIGHT = true; + boolean PREF_DEFAULT_TANGENT_GENERATION = true; + boolean PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS = true; + boolean PREF_DEFAULT_FLIPPED_TEXTURES = true; + boolean PREF_DEFAULT_ANALYTICS_GOOGLE = false; + } + + @NotNull + private static final Array ANISOTROPYCS = ArrayFactory.newArray(Integer.class); + + @NotNull + private static final Set REQUIRED_RESTART_PREFS = new HashSet<>(); + + @NotNull + private static final Set REQUIRED_UPDATE_CLASSPATH_PREFS = new HashSet<>(); + + @NotNull + private static final Set REQUIRED_RESHAPE_PREFS = new HashSet<>(); + + static { + ANISOTROPYCS.add(0); + ANISOTROPYCS.add(2); + ANISOTROPYCS.add(4); + ANISOTROPYCS.add(8); + ANISOTROPYCS.add(16); + REQUIRED_RESTART_PREFS.add(PREF_ANISOTROPY); + REQUIRED_RESTART_PREFS.add(PREF_GAMMA_CORRECTION); + REQUIRED_RESTART_PREFS.add(PREF_UI_THEME); + REQUIRED_RESTART_PREFS.add(PREF_OPEN_GL); + REQUIRED_RESTART_PREFS.add(PREF_FRAME_RATE); + REQUIRED_UPDATE_CLASSPATH_PREFS.add(PREF_USER_LIBRARY_FOLDER); + REQUIRED_UPDATE_CLASSPATH_PREFS.add(PREF_USER_CLASSES_FOLDER); + REQUIRED_RESHAPE_PREFS.add(PREF_CAMERA_ANGLE); + } + + @Override + @FxThread + public @NotNull Array getDefinitions() { + + var editorConfig = EditorConfig.getInstance(); + + var glVersion = editorConfig.getEnum(PREF_OPEN_GL, PREF_DEFAULT_OPEN_GL); + var anisotropy = editorConfig.getInteger(PREF_ANISOTROPY, PREF_DEFAULT_ANISOTROPY); + var gammaCorrection = editorConfig.getBoolean(PREF_GAMMA_CORRECTION, PREF_DEFAULT_GAMMA_CORRECTION); + var frameRate = editorConfig.getInteger(PREF_FRAME_RATE, PREF_DEFAULT_FRAME_RATE); + var cameraAngle = editorConfig.getInteger(PREF_CAMERA_ANGLE, PREF_DEFAULT_CAMERA_ANGLE); + var fxaa = editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER); + var stopRenderOnLostFocus = editorConfig.getBoolean(PREF_STOP_RENDER_ON_LOST_FOCUS, PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS); + var tonemapFilter = editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER); + var toneMapWhitePoint = editorConfig.getVector3f(PREF_FILTER_TONEMAP_WHITE_POINT, PREF_DEFAULT_TONEMAP_WHITE_POINT); + + var result = Array.ofType(SettingsPropertyDefinition.class); + result.add(new SettingsPropertyDefinition(ENUM, Messages.SETTINGS_PROPERTY_OPEN_GL, PREF_OPEN_GL, GRAPHICS, glVersion)); + result.add(new SettingsPropertyDefinition(OBJECT_FROM_LIST, Messages.SETTINGS_PROPERTY_ANISOTROPY, PREF_ANISOTROPY, GRAPHICS, anisotropy, ANISOTROPYCS)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_GAMMA_CORRECTION, PREF_GAMMA_CORRECTION, GRAPHICS, gammaCorrection)); + result.add(new SettingsPropertyDefinition(INTEGER, Messages.SETTINGS_PROPERTY_FRAME_RATE, PREF_FRAME_RATE, GRAPHICS, frameRate, 10, 120)); + result.add(new SettingsPropertyDefinition(INTEGER, Messages.SETTINGS_PROPERTY_CAMERA_ANGLE, PREF_CAMERA_ANGLE, GRAPHICS, cameraAngle, 45, 110)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_FXAA, PREF_FILTER_FXAA, GRAPHICS, fxaa)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_STOP_RENDER_ON_LOST_FOCUS, PREF_STOP_RENDER_ON_LOST_FOCUS, GRAPHICS, stopRenderOnLostFocus)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_TONEMAP_FILTER, PREF_FILTER_TONEMAP, GRAPHICS, tonemapFilter)); + result.add(new SettingsPropertyDefinition(VECTOR_3F, asArray(PREF_FILTER_TONEMAP), Messages.SETTINGS_PROPERTY_TONEMAP_FILTER_WHITE_POINT, PREF_FILTER_TONEMAP_WHITE_POINT, GRAPHICS, toneMapWhitePoint)); + + var tangentGeneration = editorConfig.getBoolean(PREF_TANGENT_GENERATION, PREF_DEFAULT_TANGENT_GENERATION); + var flippedTextures = editorConfig.getBoolean(PREF_FLIPPED_TEXTURES, PREF_DEFAULT_FLIPPED_TEXTURES); + var cameraLight = editorConfig.getBoolean(PREF_CAMERA_LAMP, PREF_DEFAULT_CAMERA_LIGHT); + var fastSkyFolder = editorConfig.getFile(PREF_FAST_SKY_FOLDER); + + result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_FAST_SKY_FOLDER, PREF_FAST_SKY_FOLDER, EDITOR, fastSkyFolder)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_TANGENT_GENERATION, PREF_TANGENT_GENERATION, EDITOR, tangentGeneration)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_FLIPPED_TEXTURE, PREF_FLIPPED_TEXTURES, EDITOR, flippedTextures)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_EDITOR_CAMERA_LAMP, PREF_CAMERA_LAMP, EDITOR, cameraLight)); + + var theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); + var libraryFolder = editorConfig.getFile(PREF_USER_LIBRARY_FOLDER); + var classesFolder = editorConfig.getFile(PREF_USER_CLASSES_FOLDER); + var googleAnalytics = editorConfig.getBoolean(PREF_ANALYTICS_GOOGLE, PREF_DEFAULT_ANALYTICS_GOOGLE); + var nativeFileChooser = editorConfig.getBoolean(PREF_NATIVE_FILE_CHOOSER, PREF_DEFAULT_NATIVE_FILE_CHOOSER); + + result.add(new SettingsPropertyDefinition(ENUM, Messages.SETTINGS_PROPERTY_THEME, PREF_UI_THEME, OTHER, theme)); + result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_USER_LIBRARIES_FOLDER, PREF_USER_LIBRARY_FOLDER, OTHER, libraryFolder)); + result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_USER_CLASSES_FOLDER, PREF_USER_CLASSES_FOLDER, OTHER, classesFolder)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_GOOGLE_ANALYTICS, PREF_ANALYTICS_GOOGLE, OTHER, googleAnalytics)); + result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_NATIVE_FILE_CHOOSER, PREF_NATIVE_FILE_CHOOSER, OTHER, nativeFileChooser)); + + return result; + } + + @Override + @FxThread + public boolean isRequiredRestart(@NotNull String propertyId) { + return REQUIRED_RESTART_PREFS.contains(propertyId); + } + + @Override + @FxThread + public boolean isRequiredReshape3DView(@NotNull String propertyId) { + return REQUIRED_RESHAPE_PREFS.contains(propertyId); + } + + @Override + @FxThread + public boolean isRequiredUpdateClasspath(@NotNull String propertyId) { + return REQUIRED_UPDATE_CLASSPATH_PREFS.contains(propertyId); + } +} diff --git a/src/main/java/com/ss/editor/document/DocumentConfig.java b/src/main/java/com/ss/builder/config/DocumentConfig.java similarity index 97% rename from src/main/java/com/ss/editor/document/DocumentConfig.java rename to src/main/java/com/ss/builder/config/DocumentConfig.java index edf53291..f64b71a6 100644 --- a/src/main/java/com/ss/editor/document/DocumentConfig.java +++ b/src/main/java/com/ss/builder/config/DocumentConfig.java @@ -1,4 +1,4 @@ -package com.ss.editor.document; +package com.ss.builder.config; import com.ss.rlib.common.data.AbstractStreamDocument; import com.ss.rlib.common.util.VarTable; diff --git a/src/main/java/com/ss/editor/config/EditorConfig.java b/src/main/java/com/ss/builder/config/EditorConfig.java similarity index 85% rename from src/main/java/com/ss/editor/config/EditorConfig.java rename to src/main/java/com/ss/builder/config/EditorConfig.java index ce20fa8f..f419319d 100644 --- a/src/main/java/com/ss/editor/config/EditorConfig.java +++ b/src/main/java/com/ss/builder/config/EditorConfig.java @@ -1,24 +1,23 @@ -package com.ss.editor.config; +package com.ss.builder.config; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.*; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.asset.AssetEventListener; import com.jme3.asset.AssetKey; import com.jme3.asset.TextureKey; import com.jme3.jfx.injfx.JmeToJfxIntegrator; import com.jme3.math.Vector3f; import com.jme3.system.AppSettings; -import com.ss.editor.JmeApplication; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.TimeTracker; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.ObjectUtils; import com.ss.rlib.common.util.Utils; import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.DictionaryUtils; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +29,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -149,43 +149,53 @@ public EditorConfig() { * @return the setting's value or default. */ @FromAnyThread - private @Nullable T get(@NotNull String id, @NotNull Class type, @Nullable T def) { + private synchronized @Nullable T get(@NotNull String id, @NotNull Class type, @Nullable T def) { + + var value = settings.getInReadLock(id, ObjectDictionary::get); - var value = DictionaryUtils.getInReadLock(settings, id, (objects, s) -> objects.get(id)); if (value == null) { return def; } else if (type.isInstance(value)) { - return unsafeCast(value); + return ClassUtils.unsafeCast(value); } T result = null; if (type == Boolean.class) { + if (value instanceof String) { - result = unsafeCast(Boolean.valueOf(value.toString())); + result = ClassUtils.unsafeCast(Boolean.valueOf(value.toString())); } + } else if (type == Integer.class) { + if (value instanceof String) { - result = unsafeCast(Integer.valueOf(value.toString())); + result = ClassUtils.unsafeCast(Integer.valueOf(value.toString())); } + } else if (type == Vector3f.class) { + if (value instanceof String) { var values = value.toString().split(","); var x = Float.parseFloat(values[0]); var y = Float.parseFloat(values[1]); var z = Float.parseFloat(values[2]); - result = unsafeCast(new Vector3f(x, y, z)); + result = ClassUtils.unsafeCast(new Vector3f(x, y, z)); } + } else if (Enum.class.isAssignableFrom(type)) { - final Class enumType = unsafeCast(type); + + Class enumType = ClassUtils.unsafeCast(type); + if (value instanceof String) { var enumValue = Enum.valueOf(enumType, value.toString()); - result = unsafeCast(enumValue); + result = ClassUtils.unsafeCast(enumValue); } + } else if (Path.class.isAssignableFrom(type)) { if (value instanceof String) { var uri = Utils.get(value.toString(), URI::new); - result = unsafeCast(Paths.get(uri)); + result = ClassUtils.unsafeCast(Paths.get(uri)); } } @@ -204,7 +214,7 @@ public EditorConfig() { * @param value the setting's value. */ @FromAnyThread - public void set(@NotNull String id, @Nullable Object value) { + public synchronized void set(@NotNull String id, @Nullable Object value) { var stamp = settings.writeLock(); try { @@ -231,7 +241,7 @@ public boolean getBoolean(@NotNull String id, boolean def) { @FromAnyThread public int getInteger(@NotNull String id, int def) { - return notNull(get(id, Integer.class, def)); + return ObjectUtils.notNull(get(id, Integer.class, def)); } @FromAnyThread @@ -246,12 +256,12 @@ public int getInteger(@NotNull String id, int def) { @FromAnyThread public > @NotNull T getEnum(@NotNull String id, @NotNull T def) { - return notNull(get(id, unsafeCast(def.getClass()), def)); + return ObjectUtils.notNull(get(id, ClassUtils.unsafeCast(def.getClass()), def)); } @FromAnyThread public @NotNull Vector3f getVector3f(@NotNull String id, @NotNull Vector3f def) { - return notNull(get(id, Vector3f.class, def)); + return ObjectUtils.notNull(get(id, Vector3f.class, def)); } @FromAnyThread @@ -303,7 +313,7 @@ public void assetLoaded(@NotNull AssetKey key) { @Override public void assetRequested(@NotNull AssetKey key) { if (key instanceof TextureKey) { - ((TextureKey) key).setAnisotropy(getInteger(PREF_ANISOTROPY, PREF_DEFAULT_ANISOTROPY)); + ((TextureKey) key).setAnisotropy(getInteger(DefaultSettingsProvider.Preferences.PREF_ANISOTROPY, DefaultSettingsProvider.Defaults.PREF_DEFAULT_ANISOTROPY)); } } @@ -317,6 +327,27 @@ public void assetRequested(@NotNull AssetKey key) { return currentAsset; } + /** + * Get an optional of the current asset folder. + * + * @return the optional of the current asset folder. + */ + @FromAnyThread + public @NotNull Optional getCurrentAssetOpt() { + return Optional.ofNullable(currentAsset); + } + + /** + * Get the current asset folder with checking not null. + * + * @return the current asset folder. + * @throws NullPointerException id the current asset is null. + */ + @FromAnyThread + public @NotNull Path requiredCurrentAsset() { + return ObjectUtils.notNull(currentAsset); + } + /** * Set the current asset folder. * @@ -499,11 +530,11 @@ public AppSettings getSettings() { var settings = new AppSettings(true); settings.setFrequency(displayMode.getRefreshRate()); - settings.setGammaCorrection(getBoolean(PREF_GAMMA_CORRECTION, PREF_DEFAULT_GAMMA_CORRECTION)); + settings.setGammaCorrection(getBoolean(DefaultSettingsProvider.Preferences.PREF_GAMMA_CORRECTION, DefaultSettingsProvider.Defaults.PREF_DEFAULT_GAMMA_CORRECTION)); settings.setResizable(true); // settings.putBoolean("GraphicsDebug", true); - JmeToJfxIntegrator.prepareSettings(settings, getInteger(PREF_FRAME_RATE, PREF_DEFAULT_FRAME_RATE)); + JmeToJfxIntegrator.prepareSettings(settings, getInteger(DefaultSettingsProvider.Preferences.PREF_FRAME_RATE, DefaultSettingsProvider.Defaults.PREF_DEFAULT_FRAME_RATE)); return settings; } @@ -513,6 +544,9 @@ public AppSettings getSettings() { */ private void init() { + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .start(); + var prefs = Preferences.userNodeForPackage(JmeApplication.class); var stamp = settings.writeLock(); try { @@ -546,7 +580,7 @@ private void init() { this.currentAsset = null; } - var cameraAngle = getInteger(PREF_CAMERA_ANGLE, PREF_DEFAULT_CAMERA_ANGLE); + var cameraAngle = getInteger(DefaultSettingsProvider.Preferences.PREF_CAMERA_ANGLE, DefaultSettingsProvider.Defaults.PREF_DEFAULT_CAMERA_ANGLE); System.setProperty("jfx.frame.transfer.camera.angle", String.valueOf(cameraAngle)); @@ -558,7 +592,7 @@ private void init() { var lastOpenedAssets = getLastOpenedAssets(); try { - lastOpenedAssets.addAll(EditorUtil.deserialize(byteArray)); + lastOpenedAssets.addAll(EditorUtils.deserialize(byteArray)); for (var iterator = lastOpenedAssets.iterator(); iterator.hasNext(); ) { @@ -573,6 +607,9 @@ private void init() { } catch (RuntimeException e) { LOGGER.warning(e); } + + TimeTracker.getStartupTracker(TimeTracker.STARTPUL_LEVEL_3) + .finish(() -> "loading of the editor config"); } /** @@ -596,7 +633,7 @@ public synchronized void save() { } else if (value instanceof Path) { prefs.put(key, ((Path) value).toUri().toString()); } else if (value instanceof Vector3f) { - final Vector3f vector = (Vector3f) value; + var vector = (Vector3f) value; prefs.put(key, vector.getX() + "," + vector.getY() + "," + vector.getZ()); } else { prefs.put(key, value.toString()); @@ -627,7 +664,7 @@ public synchronized void save() { } prefs.putByteArray(PREF_ASSET_LAST_OPENED_ASSETS, - EditorUtil.serialize((Serializable) getLastOpenedAssets())); + EditorUtils.serialize((Serializable) getLastOpenedAssets())); try { prefs.flush(); diff --git a/src/main/java/com/ss/builder/editor/EditorDescriptor.java b/src/main/java/com/ss/builder/editor/EditorDescriptor.java new file mode 100644 index 00000000..e5bbbb43 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/EditorDescriptor.java @@ -0,0 +1,131 @@ +package com.ss.builder.editor; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.Callable; + +/** + * The class to describe an editor. + * + * @author JavaSar + */ +public class EditorDescriptor { + + /** + * The list of supported extensions. + */ + @NotNull + private final Array extensions; + + /** + * The editor constructor. + */ + @NotNull + private final Callable constructor; + + /** + * The editor name. + */ + @NotNull + private final String editorName; + + /** + * The editor id. + */ + @NotNull + private final String editorId; + + /** + * The icon. + */ + @Nullable + private Image icon; + + public EditorDescriptor( + @NotNull Callable constructor, + @NotNull String editorName, + @NotNull String editorId, + @NotNull String... extensions + ) { + this.extensions = Array.of(extensions); + this.constructor = constructor; + this.editorName = editorName; + this.editorId = editorId; + } + + public EditorDescriptor( + @NotNull Callable constructor, + @NotNull String editorName, + @NotNull String editorId, + @NotNull Array extensions + ) { + this.extensions = Array.of(extensions.toArray(String.class)); + this.constructor = constructor; + this.editorName = editorName; + this.editorId = editorId; + } + + /** + * Get the editor id. + * + * @return the editor id. + */ + @FromAnyThread + public @NotNull String getEditorId() { + return editorId; + } + + /** + * Get list of supported extensions. + * + * @return the list of supported extensions. + */ + @FromAnyThread + public @NotNull Array getExtensions() { + return extensions; + } + + /** + * Get the editor's constructor. + * + * @return the editor's constructor. + */ + @FromAnyThread + public @NotNull Callable getConstructor() { + return constructor; + } + + /** + * Get the editor's name. + * + * @return the editor's name. + */ + @FromAnyThread + public @NotNull String getEditorName() { + return editorName; + } + + /** + * Get the editor's icon. + * + * @return the editor's icon or null. + */ + @FromAnyThread + public @Nullable Image getIcon() { + return icon; + } + + @Override + public String toString() { + return "EditorDescription{" + + "extensions=" + extensions + + ", constructor=" + constructor + + ", editorName='" + editorName + '\'' + + ", editorId='" + editorId + '\'' + + '}'; + } +} diff --git a/src/main/java/com/ss/builder/editor/EditorRegistry.java b/src/main/java/com/ss/builder/editor/EditorRegistry.java new file mode 100644 index 00000000..46b06264 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/EditorRegistry.java @@ -0,0 +1,216 @@ +package com.ss.builder.editor; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.editor.impl.*; +import com.ss.builder.editor.impl.audio.AudioViewerEditor; +import com.ss.builder.editor.impl.material.MaterialFileEditor; +import com.ss.builder.editor.impl.model.ModelFileEditor; +import com.ss.builder.editor.impl.scene.SceneFileEditor; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; + +/** + * THe registry of editors. + * + * @author JavaSaBr + */ +public class EditorRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(EditorRegistry.class); + + public static final String ALL_FORMATS = "*"; + + /** + * @see EditorDescriptor + */ + public static final String EP_DESCRIPTORS = "EditorRegistry#descriptors"; + + private static final ExtensionPoint DESCRIPTORS = + ExtensionPointManager.register(EP_DESCRIPTORS); + + private static final Supplier> ARRAY_FACTORY = + Array.supplier(EditorDescriptor.class); + + private static final EditorRegistry INSTANCE = new EditorRegistry(); + + public static @NotNull EditorRegistry getInstance() { + return INSTANCE; + } + + /** + * The table with editor descriptions. + */ + @NotNull + private final ConcurrentObjectDictionary> editorDescriptors; + + /** + * The table with mapping editor id to editor description. + */ + @NotNull + private final ConcurrentObjectDictionary editorIdToDescriptor; + + /** + * True if this registry was fully initialized. + */ + @NotNull + private final AtomicBoolean initialized; + + private EditorRegistry() { + this.initialized = new AtomicBoolean(false); + this.editorDescriptors = ConcurrentObjectDictionary.ofType(String.class, Array.class); + this.editorIdToDescriptor = ConcurrentObjectDictionary.ofType(String.class, EditorDescriptor.class); + + DESCRIPTORS.register(TextFileEditor.DESCRIPTOR) + .register(MaterialFileEditor.DESCRIPTOR) + .register(ModelFileEditor.DESCRIPTOR) + .register(ImageViewerEditor.DESCRIPTOR) + .register(GlslFileEditor.DESCRIPTOR) + .register(MaterialDefinitionFileEditor.DESCRIPTOR) + .register(AudioViewerEditor.DESCRIPTOR) + .register(SceneFileEditor.DESCRIPTOR); + + LOGGER.info("initialized."); + } + + @FromAnyThread + private void checkAndInitialize() { + if (initialized.compareAndSet(false, true)) { + DESCRIPTORS.getExtensions().forEach(this::register); + } + } + + /** + * Add the new descriptor. + * + * @param descriptor the descriptor of the editor. + */ + @FromAnyThread + private void register(@NotNull EditorDescriptor descriptor) { + + descriptor.getExtensions() + .forEach(descriptor, this::register); + + editorIdToDescriptor + .runInWriteLock(descriptor.getEditorId(), descriptor, ObjectDictionary::put); + } + + @FromAnyThread + private void register(@NotNull String extension, @NotNull EditorDescriptor descriptor) { + editorDescriptors.runInWriteLock(extension, descriptor, + (dict, ext, toAdd) -> dict.get(ext, ARRAY_FACTORY).add(toAdd)); + } + + /** + * Get an editor description by the editor id. + * + * @param editorId the editor id. + * @return the description or null. + */ + @FromAnyThread + public @Nullable EditorDescriptor getDescription(@NotNull String editorId) { + checkAndInitialize(); + return editorIdToDescriptor + .getInReadLock(editorId, ObjectDictionary::get); + } + + /** + * Create an editor for the file. + * + * @param file the edited file. + * @return the editor for this file or null. + */ + @FromAnyThread + public @Nullable FileEditor createEditorFor(@NotNull Path file) { + checkAndInitialize(); + + if (Files.isDirectory(file)) { + return null; + } + + var extension = FileUtils.getExtension(file); + var descriptions = editorDescriptors.get(extension); + + EditorDescriptor description; + + if (descriptions != null) { + description = descriptions.first(); + } else { + descriptions = editorDescriptors.get(ALL_FORMATS); + description = descriptions == null ? null : descriptions.first(); + } + + if (description == null) { + return null; + } + + var constructor = description.getConstructor(); + try { + return constructor.call(); + } catch (Exception e) { + EditorUtils.handleException(LOGGER, this, e); + } + + return null; + } + + /** + * Create an editor for the file. + * + * @param descriptor the editor descriptor. + * @param file the edited file. + * @return the editor or null. + */ + @FromAnyThread + public @Nullable FileEditor createEditorFor(@NotNull EditorDescriptor descriptor, @NotNull Path file) { + checkAndInitialize(); + + var constructor = descriptor.getConstructor(); + try { + return constructor.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Gets available editors for. + * + * @param file the file + * @return the list of available editors for the file. + */ + @FromAnyThread + public @NotNull Array getAvailableEditorsFor(@NotNull Path file) { + checkAndInitialize(); + + var result = Array.ofType(EditorDescriptor.class); + var extension = FileUtils.getExtension(file); + + var descriptions = editorDescriptors.get(extension); + + if (descriptions != null) { + result.addAll(descriptions); + } + + var universal = editorDescriptors.get(ALL_FORMATS); + + if (universal != null) { + result.addAll(universal); + } + + return result; + } +} diff --git a/src/main/java/com/ss/builder/editor/FileEditor.java b/src/main/java/com/ss/builder/editor/FileEditor.java new file mode 100644 index 00000000..8e4a0cf5 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/FileEditor.java @@ -0,0 +1,159 @@ +package com.ss.builder.editor; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.event.FileEditorEvent; +import com.ss.builder.fx.editor.layout.EditorLayout; +import com.ss.builder.fx.editor.part.ui.EditorUiPart; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.rlib.common.util.array.Array; +import javafx.beans.property.BooleanProperty; +import javafx.event.Event; +import javafx.scene.Parent; +import javafx.scene.layout.BorderPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; + +/** + * The interface for implementing file editor. + * + * @author JavaSaBr + */ +public interface FileEditor { + + /** + * Get a visible page of this editor + * + * @return the visible page of this editor + */ + @FxThread + @Deprecated + @NotNull Parent getUiPage(); + + /** + * Get an area to place 3D scene. + * + * @return the area to place 3D scene. + */ + @FxThread + @Deprecated + default @Nullable BorderPane get3dArea() { + return null; + } + + /** + * Get this editor's layout. + * + * @return this editor's layout. + */ + @FxThread + @NotNull EditorLayout getLayout(); + + /** + * Get the file name of the current opened file. + * + * @return the file name of the current opened file. + */ + @FxThread + @NotNull String getFileName(); + + /** + * Get the editing file. + * + * @return the editing file. + */ + @FxThread + @NotNull Path getFile(); + + /** + * Open the file. + * + * @param file the file. + */ + @BackgroundThread + void openFile(@NotNull Path file); + + /** + * Dirty property boolean property. + * + * @return the dirty property of this editor. + */ + @FxThread + @NotNull BooleanProperty dirtyProperty(); + + /** + * Return true if the current file was changed. + * + * @return true if the current file was changed. + */ + @FromAnyThread + boolean isDirty(); + + /** + * Save new changes. + */ + @FromAnyThread + @NotNull CompletableFuture save(); + + /** + * Get the editor's 3D parts. + * + * @return the editor's 3D parts. + */ + @FxThread + default @NotNull Array get3dParts() { + return Array.empty(); + } + + /** + * Get the editor's UI parts. + * + * @return the editor's UI parts. + */ + @FxThread + default @NotNull Array getUiParts() { + return Array.empty(); + } + + /** + * Notify this editor about the happened event. + * + * @param event the editor's event. + */ + @FromAnyThread + void notify(@NotNull FileEditorEvent event); + + /** + * Notify this editor about the happened event. + * + * @param event the editor's event. + */ + @FromAnyThread + void notify(@NotNull Editor3dPartEvent event); + + /** + * Get the editor's descriptor. + * + * @return the editor's descriptor. + */ + @FromAnyThread + @NotNull EditorDescriptor getDescriptor(); + + /** + * Return true if the point is inside in the editing area. + * + * @param sceneX the scene x + * @param sceneY the scene y + * @param eventType the event type. + * @return true if the point is inside in the editing area. + */ + @FxThread + default boolean isInside(double sceneX, double sceneY, @NotNull Class eventType) { + return false; + } +} diff --git a/src/main/java/com/ss/builder/editor/FileEditorUtils.java b/src/main/java/com/ss/builder/editor/FileEditorUtils.java new file mode 100644 index 00000000..d0c6499b --- /dev/null +++ b/src/main/java/com/ss/builder/editor/FileEditorUtils.java @@ -0,0 +1,29 @@ +package com.ss.builder.editor; + +import com.ss.builder.jme.editor.part3d.impl.Base3dSceneEditor3dPart; +import com.ss.builder.editor.state.impl.Editor3dEditorState; +import org.jetbrains.annotations.NotNull; + +/** + * The utility class. + * + * @author JavaSaBr + */ +public class FileEditorUtils { + + public static void loadCameraState( + @NotNull Editor3dEditorState editorState, + @NotNull Base3dSceneEditor3dPart editor3dPart + ) { + + var cameraLocation = editorState.getCameraLocation(); + + var hRotation = editorState.getCameraHRotation(); + var vRotation = editorState.getCameraVRotation(); + var tDistance = editorState.getCameraTargetDistance(); + var cameraSpeed = editorState.getCameraFlySpeed(); + + /** FIXME ExecutorManager.getInstance() + .addJmeTask(() -> editor3dPart.applyState(cameraLocation, hRotation, vRotation, tDistance, cameraFlySpeed));*/ + } +} diff --git a/src/main/java/com/ss/builder/editor/UndoableFileEditor.java b/src/main/java/com/ss/builder/editor/UndoableFileEditor.java new file mode 100644 index 00000000..51def9e1 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/UndoableFileEditor.java @@ -0,0 +1,20 @@ +package com.ss.builder.editor; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +/** + * The interface to mark an editor that it supports undo/redo methods. + * + * @author JavaSaBr + */ +public interface UndoableFileEditor extends FileEditor { + + @FromAnyThread + @NotNull CompletableFuture undo(); + + @FromAnyThread + @NotNull CompletableFuture redo(); +} diff --git a/src/main/java/com/ss/builder/editor/event/AbstractFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/AbstractFileEditorEvent.java new file mode 100644 index 00000000..559e27f9 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/AbstractFileEditorEvent.java @@ -0,0 +1,28 @@ +package com.ss.builder.editor.event; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of a file editor's event. + * + * @author JavaSaBr + */ +public abstract class AbstractFileEditorEvent implements FileEditorEvent { + + /** + * The event's source. + */ + @NotNull + protected final S source; + + protected AbstractFileEditorEvent(@NotNull S source) { + this.source = source; + } + + @Override + @FromAnyThread + public @NotNull S getSource() { + return source; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/CameraChangedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/CameraChangedFileEditorEvent.java new file mode 100644 index 00000000..d0a99c53 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/CameraChangedFileEditorEvent.java @@ -0,0 +1,34 @@ +package com.ss.builder.editor.event; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.jme.editor.part3d.control.impl.CameraEditor3dPartControl.CameraState; +import org.jetbrains.annotations.NotNull; + +/** + * The event about that editor's camera was changed. + * + * @author JavaSaBr + */ +public class CameraChangedFileEditorEvent extends AbstractFileEditorEvent { + + /** + * The new camera state. + */ + @NotNull + private final CameraState cameraState; + + public CameraChangedFileEditorEvent(@NotNull Object source, @NotNull CameraState cameraState) { + super(source); + this.cameraState = cameraState; + } + + /** + * Get the new camera state. + * + * @return the new camera state. + */ + @FromAnyThread + public @NotNull CameraState getCameraState() { + return cameraState; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/ClosedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/ClosedFileEditorEvent.java new file mode 100644 index 00000000..6cf9e1ca --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/ClosedFileEditorEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.editor.event; + +import org.jetbrains.annotations.NotNull; + +/** + * The event about the file editor was closed. + * + * @author JavaSaBr + */ +public class ClosedFileEditorEvent extends WithoutSourceFileEditorEvent { + + private static final ClosedFileEditorEvent INSTANCE = new ClosedFileEditorEvent(); + + public static @NotNull ClosedFileEditorEvent getInstance() { + return INSTANCE; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/FileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/FileEditorEvent.java new file mode 100644 index 00000000..b4820c3c --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/FileEditorEvent.java @@ -0,0 +1,22 @@ +package com.ss.builder.editor.event; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement a file editor's event. + * + * @author Alex Brui + */ +public interface FileEditorEvent { + + /** + * Get source of this event. + * + * @return the source or reference to this event. + */ + @FromAnyThread + default @NotNull Object getSource() { + return this; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/FileMovedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/FileMovedFileEditorEvent.java new file mode 100644 index 00000000..2043f47a --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/FileMovedFileEditorEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.editor.event; + +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The event about a moved file. + * + * @author JavaSaBr + */ +public class FileMovedFileEditorEvent extends FilePathChangedFileEditorEvent { + + public FileMovedFileEditorEvent(@NotNull Object source, @NotNull Path prevFile, @NotNull Path newFile) { + super(source, prevFile, newFile); + } +} diff --git a/src/main/java/com/ss/builder/editor/event/FilePathChangedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/FilePathChangedFileEditorEvent.java new file mode 100644 index 00000000..b9cd3389 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/FilePathChangedFileEditorEvent.java @@ -0,0 +1,52 @@ +package com.ss.builder.editor.event; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The event about a file with changed path. + * + * @author JavaSaBr + */ +public class FilePathChangedFileEditorEvent extends AbstractFileEditorEvent { + + /** + * The previous file path. + */ + @NotNull + private final Path prevFile; + + /** + * THe new file path. + */ + @NotNull + private final Path newFile; + + public FilePathChangedFileEditorEvent(@NotNull Object source, @NotNull Path prevFile, @NotNull Path newFile) { + super(source); + this.prevFile = prevFile; + this.newFile = newFile; + } + + /** + * Get the previous file path. + * + * @return the previous file path. + */ + @FromAnyThread + public @NotNull Path getPrevFile() { + return prevFile; + } + + /** + * Get the new file path. + * + * @return the new file path. + */ + @FromAnyThread + public @NotNull Path getNewFile() { + return newFile; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/FileRenamedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/FileRenamedFileEditorEvent.java new file mode 100644 index 00000000..af0b488a --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/FileRenamedFileEditorEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.editor.event; + +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The event about a renamed file. + * + * @author JavaSaBr + */ +public class FileRenamedFileEditorEvent extends FilePathChangedFileEditorEvent { + + public FileRenamedFileEditorEvent(@NotNull Object source, @NotNull Path prevFile, @NotNull Path newFile) { + super(source, prevFile, newFile); + } +} diff --git a/src/main/java/com/ss/builder/editor/event/HideFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/HideFileEditorEvent.java new file mode 100644 index 00000000..9e1b0dd0 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/HideFileEditorEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.editor.event; + +import org.jetbrains.annotations.NotNull; + +/** + * The event about the file editor was hide. + * + * @author JavaSaBr + */ +public class HideFileEditorEvent extends WithoutSourceFileEditorEvent { + + private static final HideFileEditorEvent INSTANCE = new HideFileEditorEvent(); + + public static @NotNull HideFileEditorEvent getInstance() { + return INSTANCE; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/KeyActionFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/KeyActionFileEditorEvent.java new file mode 100644 index 00000000..8c6f43cc --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/KeyActionFileEditorEvent.java @@ -0,0 +1,87 @@ +package com.ss.builder.editor.event; + +import com.ss.builder.annotation.FromAnyThread; +import javafx.scene.input.KeyCode; +import org.jetbrains.annotations.NotNull; + +/** + * The event about a key event. + * + * @author JavaSaBr + */ +public class KeyActionFileEditorEvent extends AbstractFileEditorEvent { + + @NotNull + private final KeyCode keyCode; + + private final boolean isPressed; + private final boolean isControlDown; + private final boolean isShiftDown; + private final boolean isButtonMiddleDown; + + public KeyActionFileEditorEvent( + @NotNull Object source, + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + super(source); + this.keyCode = keyCode; + this.isPressed = isPressed; + this.isControlDown = isControlDown; + this.isShiftDown = isShiftDown; + this.isButtonMiddleDown = isButtonMiddleDown; + } + + /** + * Get the key code. + * + * @return the key code. + */ + @FromAnyThread + public @NotNull KeyCode getKeyCode() { + return keyCode; + } + + /** + * Return true is the mouse middle button is pressed. + * + * @return true is the mouse middle button is pressed. + */ + @FromAnyThread + public boolean isButtonMiddleDown() { + return isButtonMiddleDown; + } + + /** + * Return true is the control button is pressed. + * + * @return true is the control button is pressed. + */ + @FromAnyThread + public boolean isControlDown() { + return isControlDown; + } + + /** + * Return true is the button is pressed. + * + * @return true is the button is pressed. + */ + @FromAnyThread + public boolean isPressed() { + return isPressed; + } + + /** + * Return true is the shift button is pressed. + * + * @return true is the shift button is pressed. + */ + @FromAnyThread + public boolean isShiftDown() { + return isShiftDown; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/ShowedFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/ShowedFileEditorEvent.java new file mode 100644 index 00000000..a5ccdf04 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/ShowedFileEditorEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.editor.event; + +import org.jetbrains.annotations.NotNull; + +/** + * The event about the file editor was showed. + * + * @author JavaSaBr + */ +public class ShowedFileEditorEvent extends WithoutSourceFileEditorEvent { + + private static final ShowedFileEditorEvent INSTANCE = new ShowedFileEditorEvent(); + + public static @NotNull ShowedFileEditorEvent getInstance() { + return INSTANCE; + } +} diff --git a/src/main/java/com/ss/builder/editor/event/WithoutSourceFileEditorEvent.java b/src/main/java/com/ss/builder/editor/event/WithoutSourceFileEditorEvent.java new file mode 100644 index 00000000..77164339 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/event/WithoutSourceFileEditorEvent.java @@ -0,0 +1,15 @@ +package com.ss.builder.editor.event; + +/** + * The event without any source. + * + * @author JavaSaBr + */ +public abstract class WithoutSourceFileEditorEvent extends AbstractFileEditorEvent { + + private static final Object SOURCE = new Object(); + + protected WithoutSourceFileEditorEvent() { + super(SOURCE); + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/AbstractFileEditor.java b/src/main/java/com/ss/builder/editor/impl/AbstractFileEditor.java new file mode 100644 index 00000000..ece9728b --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/AbstractFileEditor.java @@ -0,0 +1,614 @@ +package com.ss.builder.editor.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.event.*; +import com.ss.builder.editor.impl.control.EditorControl; +import com.ss.builder.editor.impl.control.impl.FxInputEditorControl; +import com.ss.builder.fx.editor.layout.EditorLayout; +import com.ss.builder.fx.editor.part.ui.EditorUiPart; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.FileChangedEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.event.EventHandler; +import javafx.scene.layout.Pane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.LocalTime; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The base implementation of a file editor. + * + * @param the editor layout's type. + * @author JavaSaBr + */ +public abstract class AbstractFileEditor implements FileEditor { + + protected static final Logger LOGGER = LoggerManager.getLogger(FileEditor.class); + + /** + * The executor manager. + */ + @NotNull + protected final ExecutorManager executorManager; + + /** + * The FX event manager. + */ + @NotNull + protected final FxEventManager fxEventManager; + + /** + * The array of editor's 3d parts. + */ + @NotNull + private final Array editor3dParts; + + /** + * The array of editor's Ui parts. + */ + @NotNull + private final Array editorUiParts; + + /** + * The array of file editor controls. + */ + @NotNull + private final Array controls; + + /** + * The file changes listener. + */ + @NotNull + private final EventHandler fileChangedHandler; + + /** + * The dirty property. + */ + @NotNull + private final BooleanProperty dirtyProperty; + + /** + * The flat about that this editor was initialized. + */ + @NotNull + private final AtomicBoolean initialized; + + /** + * The editor's layout. + */ + @NotNull + private final L layout; + + /** + * The time when this editor was showed. + */ + @NotNull + private volatile LocalTime showedTime; + + /** + * The save callback. + */ + @Nullable + private volatile CompletableFuture saveCallback; + + /** + * The editing file. + */ + @Nullable + private volatile Path file; + + /** + * True if the saving process is running now. + */ + private volatile boolean saving; + + protected AbstractFileEditor() { + this.executorManager = ExecutorManager.getInstance(); + this.fxEventManager = FxEventManager.getInstance(); + this.showedTime = LocalTime.now(); + this.editor3dParts = Array.ofType(Editor3dPart.class); + this.editorUiParts = Array.ofType(EditorUiPart.class); + this.controls = Array.ofType(EditorControl.class); + this.dirtyProperty = new SimpleBooleanProperty(this, "dirty", false); + this.initialized = new AtomicBoolean(); + this.fileChangedHandler = this::handleChangedFile; + this.layout = createLayout(); + + if (needListenEventsFromPage()) { + addEditorControl(new FxInputEditorControl(this)); + } + } + + /** + * Add the new editor's 3D part. + * + * @param editor3dPart the editor's 3D part. + */ + @FromAnyThread + protected void addEditor3dPart(@NotNull Editor3dPart editor3dPart) { + this.editor3dParts.add(editor3dPart); + } + + /** + * Add the new editor's Ui part. + * + * @param editorUiPart the editor's Ui part. + */ + @FromAnyThread + protected void addEditorUiPart(@NotNull EditorUiPart editorUiPart) { + this.editorUiParts.add(editorUiPart); + } + + /** + * Add the new editor's control. + * + * @param control the editor's control. + */ + @FromAnyThread + protected void addEditorControl(@NotNull EditorControl control) { + this.controls.add(control); + } + + /** + * Set the editing file. + * + * @param file the editing file. + */ + @FxThread + protected void setFile(@NotNull Path file) { + this.file = file; + } + + @FxThread + protected void initialize() { + buildUi(layout); + controls.forEach(EditorControl::initialize); + } + + /** + * Create editor's Ui. + * + * @param layout the editor's layout. + */ + @FromAnyThread + protected void buildUi(@NotNull L layout) { + editorUiParts.forEach(layout, EditorUiPart::buildUi); + } + + /** + * Return true if need to listen to events from root page of this editor. + * + * @return true if need to listen to events from root page of this editor. + */ + protected boolean needListenEventsFromPage() { + return true; + } + + @Override + @FromAnyThread + public @NotNull CompletableFuture save() { + var result = new CompletableFuture(); + executorManager.addFxTask(() -> checkAndSaveIfNeed(result)); + return result; + } + + /** + * Check and if need to save the current state of this editor. + * + * @param callback the callback. + */ + @FxThread + protected void checkAndSaveIfNeed(@NotNull CompletableFuture callback) { + + if (isSaving() || !isDirty()) { + callback.complete(this); + return; + } + + this.saveCallback = callback; + + notifyStartSaving(); + + executorManager.addBackgroundTask(this::saveInBackground); + } + + @BackgroundThread + protected void saveInBackground() { + + var editorId = getDescriptor().getEditorId(); + var tempFile = FileUtils.createTempFile(editorId, "toSave.tmp"); + + var stamp = EditorUtils.renderLock(); + try { + + doSave(tempFile); + + try (var out = Files.newOutputStream(getFile(), TRUNCATE_EXISTING)) { + Files.copy(tempFile, out); + } finally { + FileUtils.delete(tempFile); + } + + } catch (Throwable e) { + EditorUtils.handleException(LOGGER, this, e); + executorManager.addFxTask(this::notifyFinishSaving); + } finally { + EditorUtils.renderUnlock(stamp); + } + + executorManager.addFxTask(this::postSave); + } + + /** + * Save new changes. + * + * @param toStore the file to store. + * @throws IOException if was some problem during writing. + */ + @BackgroundThread + protected void doSave(@NotNull Path toStore) throws Throwable { + } + + /** + * Do some actions after saving. + */ + @FxThread + protected void postSave() { + setDirty(false); + } + + /** + * Create an editor's layout. + * + * @return the editor's layout. + */ + @BackgroundThread + protected abstract @NotNull L createLayout(); + + @Override + @FxThread + public @NotNull Pane getUiPage() { + throw new UnsupportedOperationException(); + } + + @Override + @FxThread + public @NotNull EditorLayout getLayout() { + return layout; + } + + @Override + @FxThread + public @NotNull Path getFile() { + return notNull(file); + } + + @Override + @FxThread + public @NotNull String getFileName() { + return getFile().getFileName() + .toString(); + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + + if (initialized.compareAndSet(false, true)) { + initialize(); + } + + fxEventManager.addEventHandler(FileChangedEvent.EVENT_TYPE, fileChangedHandler); + + this.file = file; + this.showedTime = LocalTime.now(); + + var description = getDescriptor(); + + GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_OPENED, + description.getEditorId() + "/" + getFileName()); + + GAnalytics.sendPageView(description.getEditorId(), null, "/editing/" + description.getEditorId()); + } + + @Override + @FxThread + public @NotNull BooleanProperty dirtyProperty() { + return dirtyProperty; + } + + @Override + @FromAnyThread + public boolean isDirty() { + synchronized (dirtyProperty) { + return dirtyProperty.get(); + } + } + + /** + * Set the flag of dirty of this editor. + * + * @param dirty the dirty + */ + @FromAnyThread + protected void setDirty(boolean dirty) { + synchronized (dirtyProperty) { + dirtyProperty.setValue(dirty); + } + } + + @Override + @FxThread + public @NotNull Array get3dParts() { + return editor3dParts; + } + + @Override + @FxThread + public @NotNull Array getUiParts() { + return editorUiParts; + } + + @Override + @FromAnyThread + public void notify(@NotNull FileEditorEvent event) { + + if (Platform.isFxApplicationThread()) { + notifyImpl(event); + } else { + executorManager.addFxTask(() -> notifyImpl(event)); + } + + if (event instanceof Editor3dPartEvent) { + + Editor3dPartEvent editor3dPartEvent = (Editor3dPartEvent) event; + + editorUiParts.stream() + .filter(ExtendableEditor3dPart.class::isInstance) + .map(ExtendableEditor3dPart.class::cast) + .forEach(part -> part.notify(editor3dPartEvent)); + } + } + + @JmeThread + protected void notifyImpl(@NotNull FileEditorEvent event) { + + if (event instanceof ShowedFileEditorEvent) { + notifyShowed(); + } else if (event instanceof HideFileEditorEvent) { + notifyHide(); + } else if (event instanceof ClosedFileEditorEvent) { + notifyClosed(); + } else if (event instanceof FileMovedFileEditorEvent) { + var movedEvent = (FileMovedFileEditorEvent) event; + notifyFileMoved(movedEvent.getPrevFile(), movedEvent.getNewFile()); + } else if (event instanceof FileRenamedFileEditorEvent) { + var movedEvent = (FileRenamedFileEditorEvent) event; + notifyFileRenamed(movedEvent.getPrevFile(), movedEvent.getNewFile()); + } + } + + @Override + @FromAnyThread + public void notify(@NotNull Editor3dPartEvent event) { + + } + + /** + * Notify about renamed files. + * + * @param prevFile the prev file + * @param newFile the new file + */ + @FxThread + protected void notifyFileRenamed(@NotNull Path prevFile, @NotNull Path newFile) { + notifyFilePathChanged(prevFile, newFile); + } + + /** + * Notify about moved file. + * + * @param prevFile the prev file + * @param newFile the new file + */ + @FxThread + protected void notifyFileMoved(@NotNull Path prevFile, @NotNull Path newFile) { + notifyFilePathChanged(prevFile, newFile); + } + + /** + * Notify about changed the editing file. + * + * @param prevFile the previous file. + * @param newFile the new file. + */ + @FxThread + private void notifyFilePathChanged(@NotNull Path prevFile, @NotNull Path newFile) { + + var currentFile = getFile(); + + if (currentFile.equals(prevFile)) { + setFile(newFile); + return; + } + + if (!currentFile.startsWith(prevFile)) { + return; + } + + var relativeFile = currentFile.subpath(prevFile.getNameCount(), currentFile.getNameCount()); + var resultFile = newFile.resolve(relativeFile); + + setFile(resultFile); + } + + /** + * Notify that this editor was showed. + */ + @FxThread + protected void notifyShowed() { + this.showedTime = LocalTime.now(); + + var description = getDescriptor(); + + GAnalytics.sendPageView(description.getEditorId(), null, + "/editing/" + description.getEditorId()); + } + + /** + * Notify that this editor was hide. + */ + @FxThread + protected void notifyHide() { + + var duration = Duration.between(showedTime, LocalTime.now()); + var seconds = (int) duration.getSeconds(); + + var description = getDescriptor(); + + GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, + seconds, description.getEditorId()); + } + + /** + * Notify that this editor was closed. + */ + @FxThread + protected void notifyClosed() { + + fxEventManager.removeEventHandler(FileChangedEvent.EVENT_TYPE, fileChangedHandler); + + var duration = Duration.between(showedTime, LocalTime.now()); + var seconds = (int) duration.getSeconds(); + + var description = getDescriptor(); + + GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_CLOSED, + description.getEditorId() + "/" + getFileName()); + + GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, + seconds, description.getEditorId()); + } + + /** + * Handle an event about some changed file. + * + * @param event the file changed event. + */ + @FxThread + protected void handleChangedFile(@NotNull FileChangedEvent event) { + + var file = event.getFile(); + var openedFile = getFile(); + + if (!file.equals(openedFile)) { + return; + } + + handleChangedFileImpl(event); + + if (isSaving()) { + notifyFinishSaving(); + return; + } + + handleExternalChanges(); + } + + /** + * Handle an event about that the opened file was changed. + * + * @param event the file changed event. + */ + @FxThread + protected void handleChangedFileImpl(@NotNull FileChangedEvent event) { + } + + /** + * Handle external changes of the opened file. + */ + @FxThread + protected void handleExternalChanges() { + + } + + /** + * Return true if saving process is running now. + * + * @return true if saving process is running now. + */ + @FxThread + protected boolean isSaving() { + return saving; + } + + /** + * Set true if saving process is running now. + * + * @param saving true if saving process is running now. + */ + @FxThread + protected void setSaving(boolean saving) { + this.saving = saving; + } + + /** + * Notify start saving. + */ + @FxThread + protected void notifyStartSaving() { + UiUtils.incrementLoading(); + setSaving(true); + } + + /** + * Notify finish saving. + */ + @FxThread + protected void notifyFinishSaving() { + setSaving(false); + + UiUtils.decrementLoading(); + + if (saveCallback != null) { + saveCallback.complete(this); + saveCallback = null; + } + } + + @Override + public String toString() { + return "AbstractFileEditor{" + + "dirtyProperty=" + dirtyProperty.get() + + ", file=" + file + + '}'; + } + +} diff --git a/src/main/java/com/ss/builder/editor/impl/AbstractFileEditorLegacy.java b/src/main/java/com/ss/builder/editor/impl/AbstractFileEditorLegacy.java new file mode 100644 index 00000000..573835a9 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/AbstractFileEditorLegacy.java @@ -0,0 +1,882 @@ +package com.ss.builder.editor.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import com.jme3.math.Vector3f; +import com.ss.builder.Messages; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.event.*; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.editor.layout.EditorLayout; +import com.ss.builder.fx.editor.layout.impl.PaneEditorLayout; +import com.ss.builder.fx.editor.part.ui.EditorUiPart; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.FileChangedEvent; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxUtils; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.event.EventHandler; +import javafx.scene.control.Button; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.LocalTime; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The base implementation of an editor. + * + * @param the type parameter + * @author JavaSaBr + */ +@Deprecated +public abstract class AbstractFileEditorLegacy implements FileEditor { + + protected static final Logger LOGGER = LoggerManager.getLogger(FileEditor.class); + + /** + * The array of editor's 3D parts. + */ + @NotNull + private final Array editor3dParts; + + /** + * The array of editor's Ui parts. + */ + @NotNull + private final Array editorUiParts; + + /** + * The file changes listener. + */ + @NotNull + private final EventHandler fileChangedHandler; + + /** + * The dirty property. + */ + @NotNull + private final BooleanProperty dirtyProperty; + + /** + * The flat about that this editor was initialized. + */ + @NotNull + private final AtomicBoolean initialized; + + /** + * The time when this editor was showed. + */ + @NotNull + private volatile LocalTime showedTime; + + /** + * The save callback. + */ + @Nullable + private CompletableFuture saveCallback; + + /** + * The root element of this editor. + */ + @NotNull + private final R root; + + /** + * The editor's layout. + */ + @NotNull + private final EditorLayout layout; + + /** + * The editing file. + */ + @Nullable + private volatile Path file; + + /** + * True if the left button pressed. + */ + private boolean buttonLeftDown; + + /** + * True if the right button pressed. + */ + private boolean buttonRightDown; + + /** + * True if the middle button pressed. + */ + private boolean buttonMiddleDown; + + /** + * True if the saving process is running now. + */ + private volatile boolean saving; + + protected AbstractFileEditorLegacy() { + this.showedTime = LocalTime.now(); + this.editor3dParts = Array.ofType(Editor3dPart.class); + this.editorUiParts = Array.ofType(EditorUiPart.class); + this.dirtyProperty = new SimpleBooleanProperty(this, "dirty", false); + this.initialized = new AtomicBoolean(); + this.fileChangedHandler = this::handleChangedFile; + this.root = createRoot(); + this.layout = createLayout(); + } + + /** + * Add the new editor's 3D part. + * + * @param editor3dPart the editor's 3D part. + */ + @FromAnyThread + protected void addEditor3dPart(@NotNull Editor3dPart editor3dPart) { + this.editor3dParts.add(editor3dPart); + } + + /** + * Add the new editor's Ui part. + * + * @param editorUiPart the editor's Ui part. + */ + @FromAnyThread + protected void addEditorUiPart(@NotNull EditorUiPart editorUiPart) { + this.editorUiParts.add(editorUiPart); + } + + /** + * Set the editing file. + * + * @param file the editing file. + */ + @FxThread + protected void setFile(@NotNull Path file) { + this.file = file; + } + + @FxThread + protected void buildUi() { + + var container = new VBox(); + + var page = new StackPane(container); + page.setPickOnBounds(true); + + HBox toolbar = null; + + if (needToolbar()) { + + toolbar = new HBox(); + toolbar.prefWidthProperty() + .bind(container.widthProperty()); + + createToolbar(toolbar); + + FxUtils.addClass(toolbar, CssClasses.FILE_EDITOR_TOOLBAR); + FxUtils.addChild(container, toolbar); + } + + + if (needListenEventsFromPage()) { + root.setOnKeyPressed(this::processKeyPressed); + root.setOnKeyReleased(this::processKeyReleased); + root.setOnMouseReleased(this::processMouseReleased); + root.setOnMousePressed(this::processMousePressed); + } + + createContent(root); + + FxUtils.addChild(container, root); + + if (toolbar != null) { + root.prefHeightProperty() + .bind(container.heightProperty().subtract(toolbar.heightProperty())); + } else { + root.prefHeightProperty() + .bind(container.heightProperty()); + } + + root.prefWidthProperty() + .bind(container.widthProperty()); + } + + /** + * Return true if need to listen to events from root page of this editor. + * + * @return true if need to listen to events from root page of this editor. + */ + protected boolean needListenEventsFromPage() { + return true; + } + + /** + * Handle the mouse released event. + */ + @FxThread + private void processMouseReleased(@NotNull MouseEvent mouseEvent) { + setButtonLeftDown(mouseEvent.isPrimaryButtonDown()); + setButtonMiddleDown(mouseEvent.isMiddleButtonDown()); + setButtonRightDown(mouseEvent.isSecondaryButtonDown()); + } + + /** + * Handle the mouse pressed event. + */ + @FxThread + private void processMousePressed(@NotNull MouseEvent mouseEvent) { + setButtonLeftDown(mouseEvent.isPrimaryButtonDown()); + setButtonMiddleDown(mouseEvent.isMiddleButtonDown()); + setButtonRightDown(mouseEvent.isSecondaryButtonDown()); + } + + /** + * Handle the key released event. + * + * @param event the event + */ + @FxThread + protected void processKeyReleased(@NotNull KeyEvent event) { + + var code = event.getCode(); + var isControlDown = event.isControlDown(); + var isShiftDown = event.isShiftDown(); + + if (handleKeyActionInFx(code, false, isControlDown, isShiftDown, false)) { + event.consume(); + } + } + + @FromAnyThread + public void handleKeyAction( + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + ExecutorManager.getInstance() + .addFxTask(() -> handleKeyActionInFx(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown)); + } + + /** + * Handle a key action in Fx thread. + * + * @param keyCode the key code. + * @param isPressed true if key is pressed. + * @param isControlDown true if control is down. + * @param isShiftDown true if shift is down. + * @param isButtonMiddleDown true if mouse middle button is pressed. + * @return true if need to consume the event. + */ + @FxThread + protected boolean handleKeyActionInFx( + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + return false; + } + + /** + * Handle the key pressed event. + * + * @param event the event. + */ + @FxThread + protected void processKeyPressed(@NotNull KeyEvent event) { + + var code = event.getCode(); + var isControlDown = event.isControlDown(); + var isShiftDown = event.isShiftDown(); + + if (code == KeyCode.S && event.isControlDown() && isDirty()) { + save(); + } else if (handleKeyActionInFx(code, true, isControlDown, isShiftDown, false)) { + event.consume(); + } + } + + /** + * Create a toolbar. + * + * @param container the container for the toolbar. + */ + @FromAnyThread + protected void createToolbar(@NotNull HBox container) { + } + + /** + * Create the save action. + * + * @return the button + */ + @FxThread + protected @NotNull Button createSaveAction() { + + var action = new Button(); + action.setTooltip(new Tooltip(Messages.FILE_EDITOR_ACTION_SAVE + " (Ctrl + S)")); + action.setOnAction(event -> save()); + action.setGraphic(new ImageView(Icons.SAVE_16)); + action.disableProperty().bind(dirtyProperty().not()); + + FxUtils.addClass(action, + CssClasses.FLAT_BUTTON, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + + DynamicIconSupport.addSupport(action); + + return action; + } + + @Override + @FromAnyThread + public @NotNull CompletableFuture save() { + + var result = new CompletableFuture(); + + ExecutorManager.getInstance() + .addFxTask(() -> checkAndSaveIfNeed(result)); + + return result; + } + + /** + * Check and if need to save the current state of this editor. + * + * @param callback the callback. + */ + @FxThread + protected void checkAndSaveIfNeed(@NotNull CompletableFuture callback) { + + if (isSaving() || !isDirty()) { + callback.complete(this); + return; + } + + this.saveCallback = callback; + + notifyStartSaving(); + + ExecutorManager.getInstance() + .addBackgroundTask(this::saveInBackground); + } + + @BackgroundThread + protected void saveInBackground() { + + var editorId = getDescriptor() + .getEditorId(); + + var tempFile = Utils.get(editorId, + prefix -> Files.createTempFile(prefix, "toSave.tmp")); + + var stamp = EditorUtils.renderLock(); + try { + + doSave(tempFile); + + try (var out = Files.newOutputStream(getFile(), TRUNCATE_EXISTING)) { + Files.copy(tempFile, out); + } finally { + FileUtils.delete(tempFile); + } + + } catch (Throwable e) { + EditorUtils.handleException(LOGGER, this, e); + + ExecutorManager.getInstance() + .addFxTask(this::notifyFinishSaving); + + } finally { + EditorUtils.renderUnlock(stamp); + } + + ExecutorManager.getInstance() + .addFxTask(this::postSave); + } + + /** + * Save new changes. + * + * @param toStore the file to store. + * @throws IOException if was some problem during writing. + */ + @BackgroundThread + protected void doSave(@NotNull Path toStore) throws Throwable { + } + + /** + * Do some actions after saving. + */ + @FxThread + protected void postSave() { + setDirty(false); + } + + /** + * Return true if this editor needs a toolbar. + * + * @return true if this editor needs a toolbar. + */ + @FromAnyThread + protected boolean needToolbar() { + return false; + } + + /** + * Create a root container. + * + * @return the new root container. + */ + @FromAnyThread + protected abstract @NotNull R createRoot(); + + /** + * Create an editor's layout. + * + * @return the editor's layout. + */ + @BackgroundThread + protected @NotNull EditorLayout createLayout() { + return new PaneEditorLayout(); + } + + /** + * Create editor's content. + * + * @param root the root container. + */ + @FromAnyThread + protected abstract void createContent(@NotNull R root); + + @Override + @FxThread + public @NotNull Pane getUiPage() { + return (Pane) root.getParent() + .getParent(); + } + + @Override + @FxThread + public @NotNull EditorLayout getLayout() { + return layout; + } + + @Override + @FxThread + public @NotNull Path getFile() { + return notNull(file); + } + + @Override + @FxThread + public @NotNull String getFileName() { + return getFile().getFileName() + .toString(); + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + + if (initialized.compareAndSet(false, true)) { + buildUi(); + } + + FxEventManager.getInstance() + .addEventHandler(FileChangedEvent.EVENT_TYPE, getFileChangedHandler()); + + this.file = file; + this.showedTime = LocalTime.now(); + + var description = getDescriptor(); + + GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_OPENED, + description.getEditorId() + "/" + getFileName()); + + GAnalytics.sendPageView(description.getEditorId(), null, "/editing/" + description.getEditorId()); + } + + @Override + @FxThread + public @NotNull BooleanProperty dirtyProperty() { + return dirtyProperty; + } + + @Override + @FromAnyThread + public boolean isDirty() { + synchronized (dirtyProperty) { + return dirtyProperty.get(); + } + } + + /** + * Set the flag of dirty of this editor. + * + * @param dirty the dirty + */ + @FromAnyThread + protected void setDirty(boolean dirty) { + synchronized (dirtyProperty) { + dirtyProperty.setValue(dirty); + } + } + + @Override + @FxThread + public @NotNull Array get3dParts() { + return editor3dParts; + } + + @Override + @FxThread + public @NotNull Array getUiParts() { + return editorUiParts; + } + + @Override + @FxThread + public void notify(@NotNull FileEditorEvent event) { + + if (!Platform.isFxApplicationThread()) { + ExecutorManager.getInstance() + .addFxTask(() -> notify(event)); + return; + } + + if (event instanceof ShowedFileEditorEvent) { + notifyShowed(); + } else if (event instanceof HideFileEditorEvent) { + notifyHide(); + } else if (event instanceof ClosedFileEditorEvent) { + notifyClosed(); + } else if (event instanceof FileMovedFileEditorEvent) { + var movedEvent = (FileMovedFileEditorEvent) event; + notifyFileMoved(movedEvent.getPrevFile(), movedEvent.getNewFile()); + } else if (event instanceof FileRenamedFileEditorEvent) { + var movedEvent = (FileRenamedFileEditorEvent) event; + notifyFileRenamed(movedEvent.getPrevFile(), movedEvent.getNewFile()); + } else if (event instanceof KeyActionFileEditorEvent) { + + var keyEvent = (KeyActionFileEditorEvent) event; + + handleKeyAction(keyEvent.getKeyCode(), keyEvent.isPressed(), + keyEvent.isControlDown(), keyEvent.isShiftDown(), keyEvent.isButtonMiddleDown()); + } + } + + /** + * Notify about renamed files. + * + * @param prevFile the prev file + * @param newFile the new file + */ + @FxThread + protected void notifyFileRenamed(@NotNull Path prevFile, @NotNull Path newFile) { + notifyFilePathChanged(prevFile, newFile); + } + + /** + * Notify about moved file. + * + * @param prevFile the prev file + * @param newFile the new file + */ + @FxThread + protected void notifyFileMoved(@NotNull Path prevFile, @NotNull Path newFile) { + notifyFilePathChanged(prevFile, newFile); + } + + /** + * Notify about changed the editing file. + * + * @param prevFile the previous file. + * @param newFile the new file. + */ + @FxThread + private void notifyFilePathChanged(@NotNull Path prevFile, @NotNull Path newFile) { + + var currentFile = getFile(); + + if (currentFile.equals(prevFile)) { + setFile(newFile); + return; + } + + if (!currentFile.startsWith(prevFile)) { + return; + } + + var relativeFile = currentFile.subpath(prevFile.getNameCount(), currentFile.getNameCount()); + var resultFile = newFile.resolve(relativeFile); + + setFile(resultFile); + } + + /** + * Notify about changed editor camera settings. + * + * @param cameraLocation the camera location. + * @param hRotation the h rotation. + * @param vRotation the v rotation. + * @param targetDistance the target distance. + * @param cameraSpeed the camera speed. + */ + @FxThread + public void notifyChangedCameraSettings( + @NotNull Vector3f cameraLocation, + float hRotation, + float vRotation, + float targetDistance, + float cameraSpeed + ) { + } + + /** + * Notify that this editor was showed. + */ + @FxThread + protected void notifyShowed() { + this.showedTime = LocalTime.now(); + + var description = getDescriptor(); + + GAnalytics.sendPageView(description.getEditorId(), null, + "/editing/" + description.getEditorId()); + } + + /** + * Notify that this editor was hide. + */ + @FxThread + protected void notifyHide() { + + var duration = Duration.between(showedTime, LocalTime.now()); + var seconds = (int) duration.getSeconds(); + + var description = getDescriptor(); + + GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, + seconds, description.getEditorId()); + } + + /** + * Notify that this editor was closed. + */ + @FxThread + protected void notifyClosed() { + + FxEventManager.getInstance() + .removeEventHandler(FileChangedEvent.EVENT_TYPE, getFileChangedHandler()); + + var duration = Duration.between(showedTime, LocalTime.now()); + var seconds = (int) duration.getSeconds(); + + var description = getDescriptor(); + + GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_CLOSED, + description.getEditorId() + "/" + getFileName()); + + GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, + seconds, description.getEditorId()); + } + + /** + * Handle the event about some file was changed. + * + * @param event the file changed event. + */ + @FxThread + protected void handleChangedFile(@NotNull FileChangedEvent event) { + + var file = event.getFile(); + var editFile = getFile(); + + if (!file.equals(editFile)) { + return; + } + + processChangedFileImpl(event); + + if (isSaving()) { + notifyFinishSaving(); + return; + } + + handleExternalChanges(); + } + + /** + * Handle the event about the edited file was changed. + * + * @param event the file changed event. + */ + @FxThread + protected void processChangedFileImpl(@NotNull FileChangedEvent event) { + } + + /** + * Handle external changes of the edited file. + */ + @FxThread + protected void handleExternalChanges() { + + } + + /** + * Get the file changes listener. + * + * @return the file changes listener. + */ + @FxThread + private @NotNull EventHandler getFileChangedHandler() { + return fileChangedHandler; + } + + /** + * Set true if the left button is pressed. + * + * @param buttonLeftDown true if the left button is pressed. + */ + @FxThread + protected void setButtonLeftDown(boolean buttonLeftDown) { + this.buttonLeftDown = buttonLeftDown; + } + + /** + * Set true if the middle button is pressed. + * + * @param buttonMiddleDown true if the middle button is pressed. + */ + @FxThread + protected void setButtonMiddleDown(boolean buttonMiddleDown) { + this.buttonMiddleDown = buttonMiddleDown; + } + + /** + * Set true if the right button is pressed. + * + * @param buttonRightDown true if the right button is pressed. + */ + @FxThread + protected void setButtonRightDown(boolean buttonRightDown) { + this.buttonRightDown = buttonRightDown; + } + + /** + * Return true if left button is pressed. + * + * @return true if left button is pressed. + */ + @FxThread + protected boolean isButtonLeftDown() { + return buttonLeftDown; + } + + /** + * Return true if middle button is pressed. + * + * @return true if middle button is pressed. + */ + @FxThread + protected boolean isButtonMiddleDown() { + return buttonMiddleDown; + } + + /** + * Return true if right button is pressed. + * + * @return true if right button is pressed. + */ + @FxThread + protected boolean isButtonRightDown() { + return buttonRightDown; + } + + /** + * Return true if saving process is running now. + * + * @return true if saving process is running now. + */ + @FxThread + protected boolean isSaving() { + return saving; + } + + /** + * Set true if saving process is running now. + * + * @param saving true if saving process is running now. + */ + @FxThread + protected void setSaving(boolean saving) { + this.saving = saving; + } + + /** + * Notify start saving. + */ + @FxThread + protected void notifyStartSaving() { + UiUtils.incrementLoading(); + setSaving(true); + } + + /** + * Notify finish saving. + */ + @FxThread + protected void notifyFinishSaving() { + setSaving(false); + + UiUtils.decrementLoading(); + + if (saveCallback != null) { + saveCallback.complete(this); + saveCallback = null; + } + } + + @Override + public String toString() { + return "AbstractFileEditor{" + + "dirtyProperty=" + dirtyProperty.get() + + ", file=" + file + + '}'; + } + +} diff --git a/src/main/java/com/ss/builder/editor/impl/CodeAreaFileEditor.java b/src/main/java/com/ss/builder/editor/impl/CodeAreaFileEditor.java new file mode 100644 index 00000000..3a14a281 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/CodeAreaFileEditor.java @@ -0,0 +1,166 @@ +package com.ss.builder.editor.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.control.code.BaseCodeArea; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The implementation of editor to edit files with code. + * + * @author JavaSaBr + */ +public abstract class CodeAreaFileEditor extends AbstractFileEditorLegacy { + + /** + * The code area. + */ + @NotNull + private final BaseCodeArea codeArea; + + /** + * The original content of the opened file. + */ + @Nullable + private volatile String originalContent; + + protected CodeAreaFileEditor() { + this.codeArea = createCodeArea(); + } + + @Override + @FxThread + protected @NotNull VBox createRoot() { + return new VBox(); + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + + codeArea.prefHeightProperty() + .bind(root.heightProperty()); + codeArea.prefWidthProperty() + .bind(root.widthProperty()); + codeArea.textProperty() + .addListener((observable, oldValue, newValue) -> updateDirty(newValue)); + + FxUtils.addClass(codeArea, CssClasses.TEXT_EDITOR_TEXT_AREA); + FxUtils.addChild(root, codeArea); + } + + /** + * Create the code area. + * + * @return the code area. + */ + @FxThread + protected @NotNull BaseCodeArea createCodeArea() { + throw new RuntimeException(); + } + + /** + * Update dirty state. + */ + @FxThread + private void updateDirty(@NotNull String newContent) { + setDirty(!getOriginalContent().equals(newContent)); + } + + @Override + @FxThread + protected boolean needToolbar() { + return true; + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + super.createToolbar(container); + FxUtils.addChild(container, createSaveAction()); + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + super.openFile(file); + + setOriginalContent(FileUtils.read(file)); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + codeArea.loadContent(getOriginalContent()); + setOriginalContent(codeArea.getText()); + updateDirty(getOriginalContent()); + }); + } + + /** + * Get the original content of the opened file. + * + * @return the original content of the opened file. + */ + @FxThread + private @NotNull String getOriginalContent() { + return notNull(originalContent); + } + + /** + * Set the original content of the opened file. + * + * @param originalContent the original content of the opened file. + */ + @FxThread + private void setOriginalContent(@NotNull String originalContent) { + this.originalContent = originalContent; + } + + @Override + @BackgroundThread + public void doSave(@NotNull Path toStore) throws Throwable { + super.doSave(toStore); + + var newContent = codeArea.getText(); + + try (var out = new PrintWriter(Files.newOutputStream(toStore))) { + out.print(newContent); + } + } + + @Override + @FxThread + protected void postSave() { + super.postSave(); + + var newContent = codeArea.getText(); + + setOriginalContent(newContent); + updateDirty(newContent); + } + + @Override + @FxThread + protected void handleExternalChanges() { + super.handleExternalChanges(); + + var newContent = FileUtils.read(getFile()); + var currentContent = codeArea.getText(); + + codeArea.reloadContent(newContent); + + setOriginalContent(currentContent); + updateDirty(newContent); + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/GlslFileEditor.java b/src/main/java/com/ss/builder/editor/impl/GlslFileEditor.java new file mode 100644 index 00000000..54d939f2 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/GlslFileEditor.java @@ -0,0 +1,37 @@ +package com.ss.builder.editor.impl; + +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.fx.control.code.BaseCodeArea; +import com.ss.builder.fx.control.code.GLSLCodeArea; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of editor to edit GLSL files. + * + * @author JavaSaBr + */ +public class GlslFileEditor extends CodeAreaFileEditor { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + GlslFileEditor::new, + Messages.GLSL_FILE_EDITOR_NAME, + GlslFileEditor.class.getSimpleName(), + FileExtensions.SHADER_EXTENSIONS + ); + + @Override + @FxThread + protected @NotNull BaseCodeArea createCodeArea() { + return new GLSLCodeArea(); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/ImageViewerEditor.java b/src/main/java/com/ss/builder/editor/impl/ImageViewerEditor.java new file mode 100644 index 00000000..65d10d43 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/ImageViewerEditor.java @@ -0,0 +1,88 @@ +package com.ss.builder.editor.impl; + +import com.ss.builder.FileExtensions; +import com.ss.builder.JmeApplication; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.event.impl.FileChangedEvent; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The implementation of the {@link JmeApplication} to view image files. + * + * @author JavaSaBr + */ +public class ImageViewerEditor extends AbstractFileEditorLegacy { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + ImageViewerEditor::new, + Messages.IMAGE_VIEWER_EDITOR_NAME, + ImageViewerEditor.class.getSimpleName(), + FileExtensions.IMAGE_EXTENSIONS + ); + + private static final int IMAGE_SIZE = 512; + + /** + * The image view. + */ + @NotNull + private final ImageView imageView; + + private ImageViewerEditor() { + this.imageView = new ImageView(); + } + + @Override + @FxThread + protected @NotNull VBox createRoot() { + return new VBox(); + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + FxUtils.addClass(root, CssClasses.IMAGE_VIEW_EDITOR_CONTAINER); + FxUtils.addChild(root, imageView); + } + + @Override + protected void processChangedFileImpl(@NotNull FileChangedEvent event) { + super.processChangedFileImpl(event); + + var executorManager = ExecutorManager.getInstance(); + executorManager.schedule(() -> executorManager.addFxTask(() -> showImage(getFile())), 1000); + } + + @FxThread + private void showImage(@NotNull Path file) { + + var preview = JavaFxImageManager.getInstance() + .getImagePreview(file, IMAGE_SIZE, IMAGE_SIZE); + + imageView.setImage(preview); + } + + @Override + @FxThread + public void openFile(@NotNull Path file) { + super.openFile(file); + showImage(file); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/MaterialDefinitionFileEditor.java b/src/main/java/com/ss/builder/editor/impl/MaterialDefinitionFileEditor.java new file mode 100644 index 00000000..1b26ccfc --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/MaterialDefinitionFileEditor.java @@ -0,0 +1,37 @@ +package com.ss.builder.editor.impl; + +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.fx.control.code.BaseCodeArea; +import com.ss.builder.fx.control.code.MaterialDefinitionCodeArea; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of editor to edit material definition files. + * + * @author JavaSaBr + */ +public class MaterialDefinitionFileEditor extends CodeAreaFileEditor { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + MaterialDefinitionFileEditor::new, + Messages.MATERIAL_DEFINITION_FILE_EDITOR_NAME, + MaterialDefinitionFileEditor.class.getSimpleName(), + FileExtensions.JME_MATERIAL_DEFINITION + ); + + @Override + @FxThread + protected @NotNull BaseCodeArea createCodeArea() { + return new MaterialDefinitionCodeArea(); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/TextFileEditor.java b/src/main/java/com/ss/builder/editor/impl/TextFileEditor.java new file mode 100644 index 00000000..67ba7e1b --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/TextFileEditor.java @@ -0,0 +1,174 @@ +package com.ss.builder.editor.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.EditorRegistry; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.TextArea; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The implementation of editor to edit text files. + * + * @author JavaSaBr + */ +public class TextFileEditor extends AbstractFileEditorLegacy { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + TextFileEditor::new, + Messages.TEXT_FILE_EDITOR_NAME, + TextFileEditor.class.getSimpleName(), + EditorRegistry.ALL_FORMATS + ); + + /** + * The text area. + */ + @NotNull + private final TextArea textArea; + + /** + * The original content of the opened file. + */ + @Nullable + private String originalContent; + + private TextFileEditor() { + this.textArea = new TextArea(); + } + + @Override + @FxThread + protected @NotNull VBox createRoot() { + return new VBox(); + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + + textArea.prefHeightProperty() + .bind(root.heightProperty()); + textArea.prefWidthProperty() + .bind(root.widthProperty()); + + FxControlUtils.onTextChange(textArea, this::updateDirty); + + FxUtils.addClass(textArea, CssClasses.TRANSPARENT_TEXT_AREA); + FxUtils.addChild(root, textArea); + } + + /** + * Update dirty state. + */ + @FxThread + private void updateDirty(@NotNull String newContent) { + setDirty(!getOriginalContent().equals(newContent)); + } + + @Override + @FxThread + protected boolean needToolbar() { + return true; + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + super.createToolbar(container); + FxUtils.addChild(container, createSaveAction()); + } + + @Override + @FxThread + public void openFile(@NotNull Path file) { + super.openFile(file); + + setOriginalContent(FileUtils.read(file)); + + /* TODO added to handle some exceptions + try { + + } catch (final MalformedInputException e) { + throw new RuntimeException("This file isn't a text file.", e); + } */ + + textArea.setText(getOriginalContent()); + } + + /** + * Get the original content of the opened file. + * + * @return the original content of the opened file. + */ + @FxThread + private @NotNull String getOriginalContent() { + return notNull(originalContent); + } + + /** + * Set the original content of the opened file. + * + * @param originalContent the original content of the opened file. + */ + @FxThread + private void setOriginalContent(@NotNull String originalContent) { + this.originalContent = originalContent; + } + + @Override + @BackgroundThread + public void doSave(@NotNull Path toStore) throws Throwable { + super.doSave(toStore); + + var newContent = textArea.getText(); + + try (var out = new PrintWriter(Files.newOutputStream(toStore))) { + out.print(newContent); + } + } + + @Override + @FxThread + protected void postSave() { + super.postSave(); + + var newContent = textArea.getText(); + + setOriginalContent(newContent); + updateDirty(newContent); + } + + @Override + @FxThread + protected void handleExternalChanges() { + super.handleExternalChanges(); + + var newContent = FileUtils.read(getFile()); + var currentContent = textArea.getText(); + + textArea.setText(newContent); + setOriginalContent(currentContent); + updateDirty(newContent); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/audio/AudioViewerEditor.java b/src/main/java/com/ss/builder/editor/impl/audio/AudioViewerEditor.java new file mode 100644 index 00000000..09210e2e --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/audio/AudioViewerEditor.java @@ -0,0 +1,172 @@ +package com.ss.builder.editor.impl.audio; + +import static com.jme3.audio.AudioSource.Status.Playing; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.audio.AudioKey; +import com.jme3.audio.AudioSource; +import com.ss.builder.FileExtensions; +import com.ss.builder.JmeApplication; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.impl.AbstractFileEditor; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.editor.layout.impl.VBoxEditorLayout; +import com.ss.builder.fx.editor.part.ui.AudioViewerUiPart; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.jme.editor.part3d.impl.audio.AudioViewer3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.image.ImageView; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The implementation of the {@link JmeApplication} to view audio files. + * + * @author JavaSaBr + */ +public class AudioViewerEditor extends AbstractFileEditor { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + AudioViewerEditor::new, + Messages.AUDIO_VIEWER_EDITOR_NAME, + AudioViewerEditor.class.getSimpleName(), + FileExtensions.AUDIO_EXTENSIONS + ); + + /** + * The editor's 3d part. + */ + @NotNull + private final AudioViewer3dPart editor3dPart; + + private AudioViewerEditor() { + this.editor3dPart = new AudioViewer3dPart(this); + addEditor3dPart(editor3dPart); + addEditorUiPart(new AudioViewerUiPart(this)); + } + + @Override + @BackgroundThread + protected @NotNull VBoxEditorLayout createLayout() { + return new VBoxEditorLayout(); + } + + /** + * Stop of plying. + */ + @FxThread + private void processStop() { + getEditor3dPart().stop(); + } + + /** + * Play the audio. + */ + @FxThread + private void processPlay() { + + var editor3dPart = getEditor3dPart(); + + if (editor3dPart.getPrevStatus() == Playing) { + editor3dPart.pause(); + } else { + editor3dPart.play(); + } + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + super.openFile(file); + + var assetFile = notNull(EditorUtils.getAssetFile(file)); + var assetPath = EditorUtils.toAssetPath(assetFile); + + var audioKey = new AudioKey(assetPath); + var audioData = EditorUtils.getAssetManager() + .loadAudio(audioKey); + + getEditor3dPart() + .load(audioData, audioKey); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + + var duration = audioData.getDuration(); + var bitsPerSample = audioData.getBitsPerSample(); + var channels = audioData.getChannels(); + var dataType = audioData.getDataType(); + var sampleRate = audioData.getSampleRate(); + + channelsField.setText(String.valueOf(channels)); + durationField.setText(String.valueOf(duration)); + dataTypeField.setText(String.valueOf(dataType)); + sampleRateField.setText(String.valueOf(sampleRate)); + bitsPerSampleField.setText(String.valueOf(bitsPerSample)); + }); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } + + /** + * Get the editor's 3d part. + * + * @return the editor's 3d part. + */ + @FromAnyThread + private @NotNull AudioViewer3dPart getEditor3dPart() { + return editor3dPart; + } + + /** + * Notify about changing a status of playing audio. + * + * @param status the new status. + */ + @FxThread + public void notifyChangedStatus(@NotNull AudioSource.Status status) { + + switch (status) { + case Playing: { + var graphic = (ImageView) playButton.getGraphic(); + graphic.setImage(Icons.PAUSE_128); + stopButton.setDisable(false); + break; + } + case Paused: { + var graphic = (ImageView) playButton.getGraphic(); + graphic.setImage(Icons.PLAY_128); + stopButton.setDisable(false); + break; + } + case Stopped: { + var graphic = (ImageView) playButton.getGraphic(); + graphic.setImage(Icons.PLAY_128); + stopButton.setDisable(true); + } + } + } + + @Override + public String toString() { + return "AudioViewerEditor{" + + "editor3dPart=" + editor3dPart + + "} " + super.toString(); + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/control/EditorControl.java b/src/main/java/com/ss/builder/editor/impl/control/EditorControl.java new file mode 100644 index 00000000..17028fb3 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/control/EditorControl.java @@ -0,0 +1,51 @@ +package com.ss.builder.editor.impl.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.event.FileEditorEvent; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement file editor's controls to extends state and functionality of file editors. + * + * @author JavaSaBr + */ +public interface EditorControl { + + /** + * Initialize this control. + */ + @FxThread + default void initialize() { + } + + /** + * Notify this control about file editor's event. + * + * @param event the file editor event. + */ + @FxThread + default void notify(@NotNull FileEditorEvent event) { + } + + /** + * Return true if this control knows about the property. + * + * @param propertyId the property id. + * @return true if this control knows about the property. + */ + @FxThread + default boolean hasProperty(@NotNull String propertyId) { + return false; + } + + /** + * Get a boolean property value. + * + * @param propertyId the property id. + * @return the property value or false if the property is not known. + */ + @FxThread + default boolean getBooleanProperty(@NotNull String propertyId) { + return false; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/control/impl/AbstractEditorControl.java b/src/main/java/com/ss/builder/editor/impl/control/impl/AbstractEditorControl.java new file mode 100644 index 00000000..9000908e --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/control/impl/AbstractEditorControl.java @@ -0,0 +1,23 @@ +package com.ss.builder.editor.impl.control.impl; + +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.impl.control.EditorControl; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of {@link EditorControl}. + * + * @author JavaSaBr + */ +public abstract class AbstractEditorControl implements EditorControl { + + /** + * The file editor. + */ + @NotNull + protected final F fileEditor; + + public AbstractEditorControl(@NotNull F fileEditor) { + this.fileEditor = fileEditor; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/control/impl/FxInputEditorControl.java b/src/main/java/com/ss/builder/editor/impl/control/impl/FxInputEditorControl.java new file mode 100644 index 00000000..f3c700e2 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/control/impl/FxInputEditorControl.java @@ -0,0 +1,159 @@ +package com.ss.builder.editor.impl.control.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.event.KeyActionFileEditorEvent; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import org.jetbrains.annotations.NotNull; + +/** + * The control to handle FX input of {@link FileEditor}. + * + * @author JavaSaBr + */ +public class FxInputEditorControl extends AbstractEditorControl { + + public static final String PROP_BUTTON_LEFT_DOWN = "InputStateEditorControl.buttonLeftDown"; + public static final String PROP_BUTTON_RIGHT_DOWN = "InputStateEditorControl.buttonRightDown"; + public static final String PROP_BUTTON_MIDDLE_DOWN = "InputStateEditorControl.buttonMiddleDown"; + public static final String PROP_CONTROL_DOWN = "InputStateEditorControl.controlDown"; + public static final String PROP_ALT_DOWN = "InputStateEditorControl.altDown"; + public static final String PROP_SHIFT_DOWN = "InputStateEditorControl.shiftDown"; + + /** + * True if the left button is pressed. + */ + private boolean buttonLeftDown; + + /** + * True if the right button is pressed. + */ + private boolean buttonRightDown; + + /** + * True if the middle button is pressed. + */ + private boolean buttonMiddleDown; + + /** + * True if the control button is pressed. + */ + private boolean controlDown; + + /** + * True if the alt button is pressed. + */ + private boolean altDown; + + /** + * True if the shift button is pressed. + */ + private boolean shiftDown; + + public FxInputEditorControl(@NotNull FileEditor fileEditor) { + super(fileEditor); + + } + + @Override + @FxThread + public void initialize() { + + var rootPage = fileEditor.getLayout() + .getRootPage(); + + rootPage.setOnMouseReleased(this::processMouseReleased); + rootPage.setOnMousePressed(this::processMousePressed); + rootPage.setOnKeyPressed(this::handleKeyPressed); + rootPage.setOnKeyReleased(this::handleKeyReleased); + } + + /** + * Handle the mouse released event. + */ + @FxThread + private void processMouseReleased(@NotNull MouseEvent mouseEvent) { + buttonLeftDown = mouseEvent.isPrimaryButtonDown(); + buttonRightDown = mouseEvent.isMiddleButtonDown(); + buttonMiddleDown = mouseEvent.isSecondaryButtonDown(); + } + + /** + * Handle the mouse pressed event. + */ + @FxThread + private void processMousePressed(@NotNull MouseEvent mouseEvent) { + buttonLeftDown = mouseEvent.isPrimaryButtonDown(); + buttonRightDown = mouseEvent.isMiddleButtonDown(); + buttonMiddleDown = mouseEvent.isSecondaryButtonDown(); + } + + /** + * Handle the key released event. + */ + @FxThread + private void handleKeyReleased(@NotNull KeyEvent keyEvent) { + updateKeyState(keyEvent); + + fileEditor.notify(new KeyActionFileEditorEvent(this, keyEvent.getCode(), false, + controlDown, shiftDown, buttonMiddleDown)); + } + + /** + * Handle the key pressed event. + */ + @FxThread + private void handleKeyPressed(@NotNull KeyEvent keyEvent) { + updateKeyState(keyEvent); + + fileEditor.notify(new KeyActionFileEditorEvent(this, keyEvent.getCode(), true, + controlDown, shiftDown, buttonMiddleDown)); + } + + @FxThread + private void updateKeyState(@NotNull KeyEvent keyEvent) { + shiftDown = keyEvent.isShiftDown(); + controlDown = keyEvent.isControlDown(); + altDown = keyEvent.isAltDown(); + } + + @Override + @FxThread + public boolean getBooleanProperty(@NotNull String propertyId) { + + switch (propertyId) { + case PROP_BUTTON_LEFT_DOWN: + return buttonLeftDown; + case PROP_BUTTON_MIDDLE_DOWN: + return buttonMiddleDown; + case PROP_BUTTON_RIGHT_DOWN: + return buttonRightDown; + case PROP_ALT_DOWN: + return altDown; + case PROP_SHIFT_DOWN: + return shiftDown; + case PROP_CONTROL_DOWN: + return controlDown; + } + + return false; + } + + @Override + @FxThread + public boolean hasProperty(@NotNull String propertyId) { + + switch (propertyId) { + case PROP_BUTTON_LEFT_DOWN: + case PROP_BUTTON_MIDDLE_DOWN: + case PROP_BUTTON_RIGHT_DOWN: + case PROP_ALT_DOWN: + case PROP_SHIFT_DOWN: + case PROP_CONTROL_DOWN: + return true; + } + + return false; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/material/MaterialFileEditor.java b/src/main/java/com/ss/builder/editor/impl/material/MaterialFileEditor.java new file mode 100644 index 00000000..b1dcfaed --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/material/MaterialFileEditor.java @@ -0,0 +1,326 @@ +package com.ss.builder.editor.impl.material; + +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.MaterialKey; +import com.jme3.asset.TextureKey; +import com.jme3.material.Material; +import com.jme3.shader.VarType; +import com.jme3.texture.Texture; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.jme.editor.part3d.impl.material.MaterialEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.node.material.RootMaterialSettings; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart; +import com.ss.builder.plugin.api.editor.material.BaseMaterialFileEditor; +import com.ss.builder.editor.state.EditorState; +import com.ss.builder.editor.state.impl.EditorMaterialEditorState; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.event.impl.FileChangedEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.util.MaterialUtils; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * The implementation of the Editor to edit materials. + * + * @author JavaSaBr + */ +public class MaterialFileEditor extends + BaseMaterialFileEditor { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + MaterialFileEditor::new, + Messages.MATERIAL_EDITOR_NAME, + MaterialFileEditor.class.getSimpleName(), + FileExtensions.JME_MATERIAL + ); + + /** + * The list of material definitions. + */ + @NotNull + private final ComboBox materialDefinitionBox; + + /** + * The current editing material. + */ + @Nullable + private Material currentMaterial; + + private MaterialFileEditor() { + super(); + this.materialDefinitionBox = new ComboBox<>(); + } + + @Override + @FxThread + protected @NotNull MaterialEditor3dPart create3dEditorPart() { + return new MaterialEditor3dPart(this); + } + + @Override + @FxThread + protected void handleChangedFile(@NotNull final FileChangedEvent event) { + super.handleChangedFile(event); + + var currentMaterial = getCurrentMaterial(); + var file = event.getFile(); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + var newMaterial = MaterialUtils.updateMaterialIdNeed(file, currentMaterial); + if (newMaterial != null) { + executorManager.addFxTask(() -> reload(newMaterial)); + } + }); + } + + @Override + @BackgroundThread + public void doSave(@NotNull Path toStore) throws Throwable { + super.doSave(toStore); + + var currentMaterial = getCurrentMaterial(); + var content = MaterialSerializer.serializeToString(currentMaterial); + + try (var out = new PrintWriter(Files.newOutputStream(toStore))) { + out.print(content); + } + } + + @Override + @FxThread + protected void handleExternalChanges() { + super.handleExternalChanges(); + + var assetFile = notNull(EditorUtils.getAssetFile(getFile())); + var materialKey = new MaterialKey(EditorUtils.toAssetPath(assetFile)); + + var material = EditorUtils.getAssetManager() + .loadAsset(materialKey); + + reload(material); + + operationControl.clear(); + } + + /** + * Try to apply dropped texture. + * + * @param editor the editor. + * @param dragEvent the drag event. + * @param path the path to the texture. + */ + private void applyTexture(@NotNull MaterialFileEditor editor, @NotNull DragEvent dragEvent, @NotNull Path path) { + + var textureName = path.getFileName().toString(); + var textureType = MaterialUtils.getPossibleTextureType(textureName); + + if (textureType == 0) { + return; + } + + var paramNames = MaterialUtils.getPossibleParamNames(textureType); + var currentMaterial = getCurrentMaterial(); + var materialDef = currentMaterial.getMaterialDef(); + + var param = Arrays.stream(paramNames) + .map(materialDef::getMaterialParam) + .filter(Objects::nonNull) + .filter(p -> p.getVarType() == VarType.Texture2D) + .findAny(); + + if (!param.isPresent()) { + return; + } + + var matParam = param.get(); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + + var config = EditorConfig.getInstance(); + var assetFile = EditorUtils.requireAssetFile(path); + var textureKey = new TextureKey(EditorUtils.toAssetPath(assetFile)); + textureKey.setFlipY(config.getBoolean(DefaultSettingsProvider.Preferences.PREF_FLIPPED_TEXTURES, DefaultSettingsProvider.Defaults.PREF_DEFAULT_FLIPPED_TEXTURES)); + + var texture = EditorUtils.getAssetManager() + .loadTexture(textureKey); + + texture.setWrap(Texture.WrapMode.Repeat); + + var paramName = matParam.getName(); + var textureParam = currentMaterial.getTextureParam(paramName); + var currentTexture = textureParam == null? null : textureParam.getTextureValue(); + + var operation = new PropertyOperation(currentMaterial, + paramName, texture, currentTexture); + + operation.setApplyHandler((material, newTexture) -> material.setTexture(paramName, newTexture)); + + execute(operation); + }); + } + + @Override + @FxThread + protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { + super.handleDragDroppedEvent(dragEvent); + UiUtils.handleDroppedFile(dragEvent, this, dragEvent, this::applyTexture); + } + + @Override + @FxThread + protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { + super.handleDragOverEvent(dragEvent); + UiUtils.acceptIfHasFile(dragEvent, FileExtensions.TEXTURE_EXTENSIONS); + } + + + @Override + @BackgroundThread + protected void doOpenFile(@NotNull Path file) throws IOException { + super.doOpenFile(file); + + var assetFile = notNull(EditorUtils.getAssetFile(file)); + var materialKey = new MaterialKey(EditorUtils.toAssetPath(assetFile)); + + var material = EditorUtils.getAssetManager() + .loadAsset(materialKey); + + editor3dPart.changeModelType(BaseMaterialEditor3dPart.ModelType.BOX); + + reload(material); + } + + @FxThread + @Override + protected @Nullable Supplier getEditorStateFactory() { + return EditorMaterialEditorState::new; + } + + /** + * Reload the material. + */ + @FxThread + private void reload(@NotNull Material material) { + + setCurrentMaterial(material); + setIgnoreListeners(true); + try { + + editor3dPart.updateMaterial(material); + settingsTree.fill(new RootMaterialSettings(material)); + + var materialDef = material.getMaterialDef(); + var availableResources = ResourceManager.getInstance() + .getAvailableResources(FileExtensions.JME_MATERIAL_DEFINITION); + + var items = materialDefinitionBox.getItems(); + items.clear(); + items.addAll(availableResources); + + materialDefinitionBox.getSelectionModel() + .select(materialDef.getAssetName()); + + } finally { + setIgnoreListeners(false); + } + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + super.createToolbar(container); + + var label = new Label(Messages.MATERIAL_EDITOR_MATERIAL_TYPE_LABEL + ":"); + + FxControlUtils.onSelectedItemChange(materialDefinitionBox, this::changeType); + + FxUtils.addClass(label, CssClasses.FILE_EDITOR_TOOLBAR_LABEL) + .addClass(materialDefinitionBox, CssClasses.FILE_EDITOR_TOOLBAR_FIELD); + + FxUtils.addChild(container, label, materialDefinitionBox); + } + + /** + * Handle changing the type. + */ + @FxThread + private void changeType(@Nullable String newType) { + if (!isIgnoreListeners()) { + processChangeTypeImpl(newType); + } + } + + /** + * Handle changing the type. + */ + @FxThread + private void processChangeTypeImpl(@Nullable String newType) { + + if (newType == null) { + return; + } + + var assetManager = EditorUtils.getAssetManager(); + var newMaterial = new Material(assetManager, newType); + + MaterialUtils.migrateTo(newMaterial, getCurrentMaterial()); + + operationControl.clear(); + + incrementChange(); + + reload(newMaterial); + } + + @FromAnyThread + private @NotNull Material getCurrentMaterial() { + return notNull(currentMaterial); + } + + /** + * Set the current editing material. + * + * @param currentMaterial the current editing material. + */ + @FxThread + private void setCurrentMaterial(@NotNull Material currentMaterial) { + this.currentMaterial = currentMaterial; + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/model/ModelFileEditor.java b/src/main/java/com/ss/builder/editor/impl/model/ModelFileEditor.java new file mode 100644 index 00000000..0edced3f --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/model/ModelFileEditor.java @@ -0,0 +1,393 @@ +package com.ss.builder.editor.impl.model; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.ModelKey; +import com.jme3.asset.TextureKey; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Spatial; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.model.ModelEditor3dPart; +import com.ss.builder.jme.editor.part3d.impl.model.ModelEditorBulletPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.Icons; +import com.ss.builder.editor.impl.scene.AbstractSceneFileEditor; +import com.ss.builder.editor.state.EditorState; +import com.ss.builder.editor.state.impl.EditorModelEditorState; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.impl.AbstractFileEditorLegacy; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.function.Supplier; + +/** + * The implementation of the {@link AbstractFileEditorLegacy} for working with {@link Spatial}. + * + * @author JavaSaBr + */ +public class ModelFileEditor extends AbstractSceneFileEditor { + + private static final String NO_FAST_SKY = Messages.MODEL_FILE_EDITOR_NO_SKY; + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + ModelFileEditor::new, + Messages.MODEL_FILE_EDITOR_NAME, + ModelFileEditor.class.getSimpleName(), + FileExtensions.JME_OBJECT + ); + + private static final Array FAST_SKY_LIST = Array.of( + NO_FAST_SKY, + "graphics/textures/sky/studio.hdr", + "graphics/textures/sky/env1.hdr", + "graphics/textures/sky/env2.hdr", + "graphics/textures/sky/env3.hdr", + "graphics/textures/sky/env4.hdr", + "graphics/textures/sky/outside.hdr", + "graphics/textures/sky/inside.hdr" + ); + + /** + * The bullet state. + */ + @NotNull + private final ModelEditorBulletPart bulletState; + + /** + * The list of fast skies. + */ + @NotNull + private final ComboBox fastSkyComboBox; + + /** + * The light toggle. + */ + @NotNull + private final ToggleButton lightButton; + + /** + * The physics toggle. + */ + @NotNull + private final ToggleButton physicsButton; + + /** + * The debug physics toggle. + */ + @NotNull + private final ToggleButton debugPhysicsButton; + + private ModelFileEditor() { + super(); + this.fastSkyComboBox = new ComboBox<>(); + this.lightButton = new ToggleButton(); + this.physicsButton = new ToggleButton(); + this.debugPhysicsButton = new ToggleButton(); + this.bulletState = new ModelEditorBulletPart(editor3dPart); + this.bulletState.setEnabled(false); + this.bulletState.setDebugEnabled(false); + this.bulletState.setSpeed(1F); + addEditor3dPart(bulletState); + } + + @Override + @FxThread + protected @NotNull ModelEditor3dPart create3dEditorPart() { + return new ModelEditor3dPart(this); + } + + @Override + @BackgroundThread + protected void doOpenFile(@NotNull Path file) throws IOException { + super.doOpenFile(file); + + var assetFile = EditorUtils.requireAssetFile(file); + var modelKey = new ModelKey(EditorUtils.toAssetPath(assetFile)); + + var assetManager = EditorUtils.getAssetManager(); + var model = assetManager.loadAsset(modelKey); + + MaterialUtils.cleanUpMaterialParams(model); + + editor3dPart.openModel(model); + handleAddedObject(model); + setCurrentModel(model); + setIgnoreListeners(true); + try { + + fastSkyComboBox.getSelectionModel() + .select(FAST_SKY_LIST.first()); + + refreshTree(); + + } finally { + setIgnoreListeners(false); + } + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + var editorState = notNull(getEditorState()); + + fastSkyComboBox.getSelectionModel() + .select(editorState.getSkyType()); + + lightButton.setSelected(editorState.isEnableLight()); + physicsButton.setSelected(editorState.isEnablePhysics()); + debugPhysicsButton.setSelected(editorState.isEnableDebugPhysics()); + } + + @Override + @FxThread + protected @Nullable Supplier getEditorStateFactory() { + return EditorModelEditorState::new; + } + + @Override + @FxThread + protected void handleAddedObject(@NotNull Spatial model) { + super.handleAddedObject(model); + + var geometries = NodeUtils.getGeometries(model); + geometries.forEach(editor3dPart, (geometry, modelEditor3dPart) -> { + if (geometry.getQueueBucket() == RenderQueue.Bucket.Sky) { + modelEditor3dPart.addCustomSky(geometry); + } + }); + } + + @Override + @FxThread + protected void handleRemovedObject(@NotNull Spatial model) { + super.handleRemovedObject(model); + + var geometries = NodeUtils.getGeometries(model); + geometries.forEach(editor3dPart, (geometry, modelEditor3dPart) -> { + if (geometry.getQueueBucket() == RenderQueue.Bucket.Sky) { + modelEditor3dPart.removeCustomSky(geometry); + } + }); + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + super.createToolbar(container); + + var fastSkyLabel = new Label(Messages.MODEL_FILE_EDITOR_FAST_SKY + ":"); + + FxControlUtils.onSelectedItemChange(fastSkyComboBox, this::changeFastSky); + + var skyItems = fastSkyComboBox.getItems(); + skyItems.addAll(FAST_SKY_LIST); + + ResourceManager.getInstance() + .getAdditionalEnvs() + .forEach(path -> skyItems.add(path.toString())); + + FxUtils.addChild(container, fastSkyLabel, fastSkyComboBox); + } + + @Override + @FxThread + protected void createActions(@NotNull final HBox container) { + super.createActions(container); + + lightButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_CAMERA_LIGHT)); + lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); + lightButton.setSelected(true); + lightButton.selectedProperty() + .addListener((observable, oldValue, newValue) -> changeLight(newValue)); + + physicsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_PHYSICS)); + physicsButton.setGraphic(new ImageView(Icons.PHYSICS_16)); + physicsButton.setSelected(false); + + debugPhysicsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_DEBUG_PHYSICS)); + debugPhysicsButton.setGraphic(new ImageView(Icons.DEBUG_16)); + debugPhysicsButton.setSelected(false); + + FxControlUtils.onSelectedChange(lightButton, this::changeLight); + FxControlUtils.onSelectedChange(physicsButton, this::changePhysics); + FxControlUtils.onSelectedChange(debugPhysicsButton, this::changeDebugPhysics); + + DynamicIconSupport.addSupport(lightButton, physicsButton, debugPhysicsButton); + + FxUtils.addClass(lightButton, physicsButton, debugPhysicsButton, + CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + + FxUtils.addChild(container, lightButton, physicsButton, debugPhysicsButton); + } + + /** + * Handle changing a sky. + */ + @FxThread + private void changeFastSky(@NotNull String newSky) { + + if (isIgnoreListeners()) { + return; + } + + var editorState = getEditorState(); + + if (NO_FAST_SKY.equals(newSky)) { + + editor3dPart.changeFastSky(null); + + if (editorState != null) { + editorState.setSkyType(0); + } + + return; + } + + var assetManager = EditorUtils.getAssetManager(); + + var key = new TextureKey(newSky, true); + key.setGenerateMips(false); + + var texture = assetManager.loadTexture(key); + var newFastSky = SkyFactory.createSky(assetManager, texture, EnvMapType.EquirectMap); + + editor3dPart.changeFastSky(newFastSky); + + var selectedIndex = fastSkyComboBox.getSelectionModel() + .getSelectedIndex(); + + if (editorState != null) { + editorState.setSkyType(selectedIndex); + } + } + + /** + * Handle to change enabling of physics. + */ + @FxThread + private void changePhysics(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + ExecutorManager.getInstance() + .addJmeTask(() -> bulletState.setEnabled(newValue)); + + if (editorState != null) { + editorState.setEnablePhysics(newValue); + } + } + + /** + * Handle to change enabling of physics. + */ + @FxThread + private void changeDebugPhysics(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + ExecutorManager.getInstance() + .addJmeTask(() -> bulletState.setDebugEnabled(newValue)); + + if (editorState != null) { + editorState.setEnableDebugPhysics(newValue); + } + } + + /** + * Handle changing camera light visibility. + */ + @FxThread + private void changeLight(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + editor3dPart.updateLightEnabled(newValue); + + if (editorState != null) { + editorState.setEnableLight(newValue); + } + } + + @Override + @FxThread + public void notifyFxAddedChild(@NotNull Object parent, @NotNull Object added, int index, boolean needSelect) { + super.notifyFxAddedChild(parent, added, index, needSelect); + + if (added instanceof Spatial) { + + var spatial = (Spatial) added; + var isSky = spatial.getQueueBucket() == RenderQueue.Bucket.Sky; + + if (isSky) { + editor3dPart.addCustomSky(spatial); + editor3dPart.updateLightProbe(); + } + } + + ExecutorManager.getInstance() + .addFxTask(() -> bulletState.notifyAdded(added)); + } + + @Override + @FxThread + public void notifyFxRemovedChild(@NotNull Object parent, @NotNull Object removed) { + super.notifyFxRemovedChild(parent, removed); + + if (removed instanceof Spatial) { + + var spatial = (Spatial) removed; + var isSky = spatial.getQueueBucket() == RenderQueue.Bucket.Sky; + + if (isSky) { + editor3dPart.removeCustomSky(spatial); + editor3dPart.updateLightProbe(); + } + } + + ExecutorManager.getInstance() + .addFxTask(() -> bulletState.notifyRemoved(removed)); + } + + @Override + public String toString() { + return "ModelFileEditor{" + + "} " + super.toString(); + } +} diff --git a/src/main/java/com/ss/builder/editor/impl/scene/AbstractSceneFileEditor.java b/src/main/java/com/ss/builder/editor/impl/scene/AbstractSceneFileEditor.java new file mode 100644 index 00000000..0b11431e --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/scene/AbstractSceneFileEditor.java @@ -0,0 +1,1351 @@ +package com.ss.builder.editor.impl.scene; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetManager; +import com.jme3.asset.MaterialKey; +import com.jme3.asset.ModelKey; +import com.jme3.audio.AudioNode; +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.jme3.texture.Texture; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.scripting.EditorScriptingComponent; +import com.ss.builder.editor.state.impl.BaseEditorSceneEditorState; +import com.ss.builder.fx.component.painting.PaintingComponent; +import com.ss.builder.fx.component.painting.PaintingComponentContainer; +import com.ss.builder.fx.component.tab.EditorToolComponent; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.model.ModelPropertyEditor; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.action.impl.multi.RemoveElementsAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.event.impl.FileChangedEvent; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.jme.control.transform.EditorTransformSupport; +import com.ss.builder.jme.editor.part3d.impl.Stats3dPart; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.editor.ModelEditingProvider; +import com.ss.builder.model.scene.EditorAudioNode; +import com.ss.builder.model.scene.EditorLightNode; +import com.ss.builder.model.scene.WrapperNode; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import com.ss.builder.plugin.api.editor.Advanced3dFileEditorWithSplitRightTool; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.*; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.ScenePresentable; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FXUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.Event; +import javafx.scene.control.*; +import javafx.scene.image.ImageView; +import javafx.scene.input.DragEvent; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +/** + * The base implementation of a model/scene file editor. + * + * @param the type of edited object. + * @param the type of {@link AbstractSceneEditor3dPart} + * @param the type of an editor state. + * @author JavaSaBr + */ +public abstract class AbstractSceneFileEditor extends + Advanced3dFileEditorWithSplitRightTool implements ModelChangeConsumer, ModelEditingProvider { + + public interface SaveHandler { + + @BackgroundThread + void handle(@NotNull Spatial spatial); + } + + protected static final int OBJECTS_TOOL = 0; + protected static final int PAINTING_TOOL = 1; + protected static final int SCRIPTING_TOOL = 2; + + private static final Array ACCEPTED_FILES = Array.of( + FileExtensions.JME_MATERIAL, + FileExtensions.JME_OBJECT + ); + + private static final ObservableList TRANSFORMATION_MODES = + FXCollections.observableArrayList(EditorTransformSupport.TransformationMode.values()); + + public static final String EP_PRE_SAVE_HANDLERS = "AbstractSceneFileEditor#preSaveHandlers"; + public static final String EP_POST_SAVE_HANDLERS = "AbstractSceneFileEditor#postSaveHandlers"; + + private static final ExtensionPoint PRE_SAVE_HANDLERS = + ExtensionPointManager.register(EP_PRE_SAVE_HANDLERS); + + private static final ExtensionPoint POST_SAVE_HANDLERS = + ExtensionPointManager.register(EP_POST_SAVE_HANDLERS); + + /** + * The stats 3D part. + */ + @NotNull + private final Stats3dPart stats3dPart; + + /** + * The selection handler. + */ + @NotNull + private final Consumer> selectionNodeHandler; + + /** + * The list of transform modes. + */ + @NotNull + private final ComboBox transformModeComboBox; + + /** + * The model tree. + */ + @NotNull + protected final ModelNodeTree modelNodeTree; + + /** + * The model property editor. + */ + @NotNull + protected final ModelPropertyEditor modelPropertyEditor; + + /** + * The container of painting components. + */ + @NotNull + private final PaintingComponentContainer paintingComponentContainer; + + /** + * The scripting component. + */ + @NotNull + private final EditorScriptingComponent scriptingComponent; + + /** + * The container of property editor in objects tool. + */ + @NotNull + private final VBox propertyEditorObjectsContainer; + + /** + * The container of model node tree in objects tool. + */ + @NotNull + private final VBox modelNodeTreeObjectsContainer; + + /** + * The container of model node tree in editing tool. + */ + @NotNull + private final VBox modelNodeTreeEditingContainer; + + /** + * The stats container. + */ + @NotNull + private final VBox statsContainer; + + /** + * The selection toggle. + */ + @NotNull + private final ToggleButton selectionButton; + + /** + * The grid toggle. + */ + @NotNull + private final ToggleButton gridButton; + + /** + * The statistics toggle. + */ + @NotNull + private final ToggleButton statisticsButton; + + /** + * The move tool toggle. + */ + @NotNull + private final ToggleButton moveToolButton; + + /** + * The rotation tool toggle. + */ + @NotNull + private final ToggleButton rotationToolButton; + + /** + * The scaling tool toggle. + */ + @NotNull + private final ToggleButton scaleToolButton; + + /** + * The opened model. + */ + @Nullable + private M currentModel; + + /** + * The flag of ignoring camera moving. + */ + private boolean ignoreCameraMove; + + public AbstractSceneFileEditor() { + this.selectionNodeHandler = this::selectNodesFromTree; + this.modelNodeTree = new ModelNodeTree(selectionNodeHandler, this); + this.modelPropertyEditor = new ModelPropertyEditor(this); + this.propertyEditorObjectsContainer = new VBox(); + this.modelNodeTreeEditingContainer = new VBox(); + this.modelNodeTreeObjectsContainer = new VBox(); + this.paintingComponentContainer = new PaintingComponentContainer(this, this); + this.statsContainer = new VBox(); + this.stats3dPart = new Stats3dPart(statsContainer); + this.scriptingComponent = new EditorScriptingComponent(this::refreshTree); + this.selectionButton = new ToggleButton(); + this.gridButton = new ToggleButton(); + this.statisticsButton = new ToggleButton(); + this.moveToolButton = new ToggleButton(); + this.rotationToolButton = new ToggleButton(); + this.scaleToolButton = new ToggleButton(); + this.transformModeComboBox = new ComboBox<>(TRANSFORMATION_MODES); + addEditor3dPart(stats3dPart); + stats3dPart.setEnabled(true); + processChangeTool(-1, OBJECTS_TOOL); + } + + @Override + @FxThread + protected void handleChangedFile(@NotNull FileChangedEvent event) { + super.handleChangedFile(event); + + var file = event.getFile(); + var extension = FileUtils.getExtension(file); + + if (extension.endsWith(FileExtensions.JME_MATERIAL)) { + + ExecutorManager.getInstance() + .addJmeTask(() -> updateMaterial(file)); + + } else if (MaterialUtils.isShaderFile(file) || MaterialUtils.isTextureFile(file)) { + + ExecutorManager.getInstance() + .addJmeTask(() -> updateMaterials(file)); + } + } + + /** + * Updating a material from the file. + */ + @FxThread + private void updateMaterial(@NotNull Path file) { + + var assetFile = EditorUtils.requireAssetFile(file); + var assetPath = EditorUtils.toAssetPath(assetFile); + var currentModel = getCurrentModel(); + + var geometries = NodeUtils.getGeometriesWithMaterial(currentModel, assetPath); + + if (geometries.isEmpty()) { + return; + } + + var material = EditorUtils.getAssetManager() + .loadMaterial(assetPath); + + geometries.forEach(geometry -> geometry.setMaterial(material)); + + RenderFilterRegistry.getInstance() + .refreshFilters(); + } + + /** + * Updating materials. + */ + @FxThread + private void updateMaterials(@NotNull Path file) { + + var currentModel = getCurrentModel(); + var needRefresh = new AtomicInteger(); + + NodeUtils.visitGeometry(currentModel, geometry -> { + + var material = geometry.getMaterial(); + var newMaterial = MaterialUtils.updateMaterialIdNeed(file, material); + + if (newMaterial != null) { + geometry.setMaterial(newMaterial); + needRefresh.incrementAndGet(); + } + }); + + if (needRefresh.get() < 1) { + return; + } + + RenderFilterRegistry.getInstance() + .refreshFilters(); + } + + /** + * Handle a added model. + * + * @param model the model + */ + @FxThread + protected void handleAddedObject(@NotNull Spatial model) { + + NodeUtils.getAllLights(model).forEach(editor3dPart, + (light, editor3dPart) -> editor3dPart.addLight(light)); + + NodeUtils.getAllAudioNodes(model).forEach(editor3dPart, + (audioNode, editor3dPart) -> editor3dPart.addAudioNode(audioNode)); + } + + /** + * Handle a removed model.T + * + * @param model the model + */ + @FxThread + protected void handleRemovedObject(@NotNull Spatial model) { + + NodeUtils.getAllLights(model).forEach(editor3dPart, + (light, editor3dPart) -> editor3dPart.removeLight(light)); + + NodeUtils.getAllAudioNodes(model).forEach(editor3dPart, + (audioNode, editor3dPart) -> editor3dPart.removeAudioNode(audioNode)); + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + scriptingComponent.addVariable("root", getCurrentModel()); + scriptingComponent.addVariable("assetManager", EditorUtils.getAssetManager(), AssetManager.class); + scriptingComponent.addImport(Spatial.class); + scriptingComponent.addImport(Geometry.class); + scriptingComponent.addImport(Control.class); + scriptingComponent.addImport(Node.class); + scriptingComponent.addImport(Light.class); + scriptingComponent.addImport(DirectionalLight.class); + scriptingComponent.addImport(PointLight.class); + scriptingComponent.addImport(SpotLight.class); + scriptingComponent.addImport(Material.class); + scriptingComponent.addImport(Texture.class); + scriptingComponent.addImport(AssetManager.class); + scriptingComponent.setExampleCode("root.attachChild(\nnew Node(\"created from Groovy\"));"); + scriptingComponent.buildHeader(); + + var editorState = notNull(getEditorState()); + + gridButton.setSelected(editorState.isEnableGrid()); + statisticsButton.setSelected(editorState.isShowStatistics()); + selectionButton.setSelected(editorState.isEnableSelection()); + transformModeComboBox.getSelectionModel() + .select(EditorTransformSupport.TransformationMode.valueOf(editorState.getTransformationMode())); + + var components = paintingComponentContainer.getComponents(); + components.forEach(editorState, PaintingComponent::loadState); + + var transformType = EditorTransformSupport.TransformType.valueOf(editorState.getTransformationType()); + + switch (transformType) { + case MOVE_TOOL: { + moveToolButton.setSelected(true); + break; + } + case ROTATE_TOOL: { + rotationToolButton.setSelected(true); + break; + } + case SCALE_TOOL: { + scaleToolButton.setSelected(true); + break; + } + default: { + break; + } + } + } + + @Override + @FxThread + protected boolean handleKeyActionInFx( + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + + /* + FIXME + if (editor3dPart.isCameraFlying()) { + return false; + }*/ + + if (isPressed && keyCode == KeyCode.G && !isControlDown && !isButtonMiddleDown) { + moveToolButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.R && !isControlDown && !isButtonMiddleDown) { + rotationToolButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.S && !isControlDown && !isButtonMiddleDown) { + scaleToolButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.DELETE) { + + var removeAction = findTreeAction(RemoveElementsAction.class); + + if (removeAction == null) { + return false; + } + + removeAction.process(); + return true; + + } else if (isPressed && isControlDown && keyCode == KeyCode.C) { + //TODO + } else if (isPressed && isControlDown && keyCode == KeyCode.V) { + //TODO + } + + return super.handleKeyActionInFx(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); + } + + /** + * Find a tree action for the current selected items. + * + * @param type the action's type. + * @param the action's type. + * @return the found action or null. + */ + @FxThread + protected @Nullable T findTreeAction(@NotNull Class type) { + + var selected = modelNodeTree.getSelected(); + + if (selected == null || !selected.canRemove()) { + return null; + } + + var contextMenu = modelNodeTree.getContextMenu(null); + + return UiUtils.findMenuItem(contextMenu.getItems(), type); + } + + /** + * Return true if need to ignore moving camera. + * + * @return true if need to ignore moving camera. + */ + @FxThread + private boolean isIgnoreCameraMove() { + return ignoreCameraMove; + } + + /** + * Set true if need to ignore moving camera. + * + * @param ignoreCameraMove true if need to ignore moving camera. + */ + @FxThread + private void setIgnoreCameraMove(boolean ignoreCameraMove) { + this.ignoreCameraMove = ignoreCameraMove; + } + + /** + * Set the current opened model. + * + * @param currentModel the current opened model. + */ + @FxThread + protected void setCurrentModel(@NotNull M currentModel) { + this.currentModel = currentModel; + } + + @Override + @FxThread + public @NotNull M getCurrentModel() { + return notNull(currentModel); + } + + @Override + @FxThread + public void notifyFxChangeProperty(@Nullable Object parent, @NotNull Object object, @NotNull String propertyName) { + + if (object instanceof EditableProperty) { + object = ((EditableProperty) object).getObject(); + } + + modelPropertyEditor.syncFor(object); + modelNodeTree.notifyChanged(parent, object); + + if (object instanceof Geometry && Messages.MODEL_PROPERTY_MATERIAL.equals(propertyName)) { + modelNodeTree.refresh(object); + } + + paintingComponentContainer.notifyChangeProperty(object, propertyName); + } + + @Override + public void notifyJmePreChangeProperty(@NotNull Object object, @NotNull String propertyName) { + editor3dPart.notifyPropertyPreChanged(object, propertyName); + } + + @Override + @FxThread + public void notifyJmeChangedProperty(@NotNull Object object, @NotNull String propertyName) { + editor3dPart.notifyPropertyChanged(object, propertyName); + } + + @Override + @FxThread + public void notifyFxChangePropertyCount(@NotNull Object object) { + modelPropertyEditor.rebuildFor(object, null); + } + + @Override + @FxThread + public void notifyFxAddedChild(@NotNull Object parent, @NotNull Object added, int index, boolean needSelect) { + + modelNodeTree.notifyAdded(parent, added, index); + + if (added instanceof Light) { + editor3dPart.addLight((Light) added); + } else if (added instanceof AudioNode) { + editor3dPart.addAudioNode((AudioNode) added); + } else if (added instanceof Spatial) { + handleAddedObject((Spatial) added); + } + + if (needSelect) { + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> executorManager.addFxTask(() -> modelNodeTree.selectSingle(added))); + } + } + + @Override + @FxThread + public void notifyFxRemovedChild(@NotNull Object parent, @NotNull Object removed) { + + modelNodeTree.notifyRemoved(parent, removed); + + if (removed instanceof Light) { + editor3dPart.removeLight((Light) removed); + } else if (removed instanceof AudioNode) { + editor3dPart.removeAudioNode((AudioNode) removed); + } else if (removed instanceof Spatial) { + handleRemovedObject((Spatial) removed); + } + } + + @Override + @FxThread + public void notifyFxReplaced( + @NotNull Object parent, + @Nullable Object oldChild, + @Nullable Object newChild, + boolean needExpand, + boolean needDeepExpand + ) { + + var currentModel = getCurrentModel(); + + if (currentModel == oldChild && newChild instanceof Spatial) { + + handleRemovedObject(currentModel); + + editor3dPart.openModel(ClassUtils.unsafeCast(newChild)); + + handleAddedObject((Spatial) newChild); + + setCurrentModel(ClassUtils.unsafeCast(newChild)); + + } else { + + if (oldChild instanceof Spatial) { + handleRemovedObject((Spatial) oldChild); + } + + if (newChild instanceof Spatial) { + handleAddedObject((Spatial) newChild); + } + } + + modelNodeTree.notifyReplace(parent, oldChild, newChild, needExpand, needDeepExpand); + } + + @Override + @FxThread + public void notifyFxMoved( + @NotNull Object prevParent, + @NotNull Object newParent, + @NotNull Object child, + int index, + boolean needSelect + ) { + + modelNodeTree.notifyMoved(prevParent, newParent, child, index); + + if (needSelect) { + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> executorManager.addFxTask(() -> modelNodeTree.selectSingle(child))); + } + } + + /** + * Handle the selected object. + * + * @param object the object + */ + @FxThread + public void notifySelected(@Nullable Object object) { + + if (object instanceof EditorLightNode) { + object = ((EditorLightNode) object).getLight(); + } + + if (object instanceof EditorAudioNode) { + object = ((EditorAudioNode) object).getAudioNode(); + } + + setIgnoreCameraMove(true); + try { + + modelNodeTree.selectSingle(object); + + var selectionModel = getEditorToolComponent().getSelectionModel(); + + if (isNeedToOpenObjectsTool(selectionModel.getSelectedIndex())) { + selectionModel.select(OBJECTS_TOOL); + } + + } finally { + setIgnoreCameraMove(false); + } + } + + /** + * Return true if need to open objects tool. + * + * @param current the current opened tool. + * @return true if need to open objects tool. + */ + @FxThread + protected boolean isNeedToOpenObjectsTool(int current) { + return !(current == OBJECTS_TOOL || current == SCRIPTING_TOOL); + } + + /** + * Return true of the spatial can be selected. + * + * @param spatial the spatial. + * @return true if the spatial can be selected. + */ + @FxThread + protected boolean canSelect(@NotNull Spatial spatial) { + return true; + } + + /** + * Handle the selected object from the tree. + * + * @param object the selected object. + */ + @FxThread + public void selectNodeFromTree(@Nullable Object object) { + selectNodesFromTree(object == null ? Array.empty() : Array.of(object)); + } + + /** + * Handle the selected objects from the tree. + * + * @param objects the selected objects. + */ + @FxThread + public void selectNodesFromTree(@NotNull Array objects) { + + /** FIXME + editor3dPart.select(Array.empty()); + + if (objects.size() > 1) { + multiSelectNodesFromTree(objects, editor3dPart); + } else if (objects.size() == 1) { + singleSelectNodesFromTree(objects, editor3dPart); + return; + } else { + editor3dPart.select(Array.empty()); + } + + modelPropertyEditor.buildFor(null, null); + paintingComponentContainer.prepareFor(null);**/ + } + + /** + * Handle multi select nodes from tree. + * + * @param objects the selected objects. + * @param editor3dPart the 3D part of this editor. + */ + @FxThread + protected void multiSelectNodesFromTree(@NotNull Array objects, @NotNull MA editor3dPart) { + + /**FIXME + * var toSelect = Array.ofType(Spatial.class); + + for (var object : objects) { + getSpatialToShowSelection(editor3dPart, object) + .ifPresent(toSelect::add); + } + + editor3dPart.select(toSelect);**/ + } + + /** + * Try to get a spatial to show selection of the object. + * + * @param editor3dPart the editor 3D part. + * @param object the object. + * @return the optional value of a spatial. + */ + @JmeThread + protected @NotNull Optional getSpatialToShowSelection(@NotNull MA editor3dPart, Object object) { + + Object element; + + if (object instanceof TreeNode) { + element = ((TreeNode) object).getElement(); + } else { + element = object; + } + + if (element instanceof SceneLayer) { + element = null; + } + + Spatial spatial = null; + + if (element instanceof AudioNode) { + var audioNode = editor3dPart.getAudioNode((AudioNode) element); + spatial = audioNode == null ? null : audioNode.getEditedNode(); + } else if (element instanceof Spatial) { + spatial = (Spatial) element; + } else if (element instanceof Light) { + spatial = editor3dPart.getLightNode((Light) element); + } else if (element instanceof ScenePresentable) { + var presentableNode = editor3dPart.getPresentableNode((ScenePresentable) element); + spatial = presentableNode == null ? null : presentableNode.getEditedNode(); + } + + if (spatial != null && !spatial.isVisible()) { + spatial = null; + } + + if (spatial != null && canSelect(spatial)) { + return Optional.of(spatial); + } + + return Optional.empty(); + } + + /** + * Handle single select node from a tree. + * + * @param objects the selected objects. + * @param editor3dPart the 3D part of this editor. + */ + @FxThread + protected void singleSelectNodesFromTree(@NotNull Array objects, @NotNull MA editor3dPart) { + + Object parent = null; + Object element; + + var first = objects.first(); + + if (first instanceof TreeNode) { + var treeNode = (TreeNode) first; + var parentNode = treeNode.getParent(); + element = treeNode.getElement(); + parent = parentNode == null ? null : parentNode.getElement(); + } else { + element = first; + } + + if (element instanceof SceneLayer) { + element = null; + } + + Spatial spatial = getSpatialToShowSelection(editor3dPart, first) + .orElse(null); + + if (spatial != null && canSelect(spatial)) { + + //FIXME editor3dPart.select(spatial); + + if (!isIgnoreCameraMove() && !isVisibleOnEditor(spatial)) { + editor3dPart.cameraLookAt(spatial); + } + } + + modelPropertyEditor.buildFor(element, parent); + paintingComponentContainer.prepareFor(element); + } + + @FxThread + private boolean isVisibleOnEditor(@NotNull Spatial spatial) { + + var camera = editor3dPart.getCamera(); + + var position = spatial.getWorldTranslation(); + var coordinates = camera.getScreenCoordinates(position, new Vector3f()); + + var invisible = coordinates.getZ() < 0F || coordinates.getZ() > 1F; + invisible = invisible || !isInside(coordinates.getX(), camera.getHeight() - coordinates.getY(), Event.class); + + return !invisible; + } + + @Override + @BackgroundThread + public void doSave(@NotNull Path toStore) throws Throwable { + super.doSave(toStore); + + var currentModel = getCurrentModel(); + try { + + NodeUtils.visitGeometry(currentModel, + Geometry::getMaterial, + MaterialUtils::saveIfNeedTextures); + + } catch (Exception e) { + throw new RuntimeException(e); + } + + var preSaveHandlers = PRE_SAVE_HANDLERS.getExtensions(); + var postSaveHandlers = POST_SAVE_HANDLERS.getExtensions(); + + preSaveHandlers.forEach(saveHandler -> saveHandler.handle(currentModel)); + try { + + var exporter = BinaryExporter.getInstance(); + + try (var out = Files.newOutputStream(toStore)) { + exporter.save(currentModel, out); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + postSaveHandlers.forEach(saveHandler -> saveHandler.handle(currentModel)); + } + } + + @Override + @FxThread + protected boolean needToolbar() { + return true; + } + + /** + * Switch transformation mode. + */ + @FxThread + private void changeTransformMode(@NotNull EditorTransformSupport.TransformationMode transformationMode) { + + //FIXME editor3dPart.setTransformMode(transformationMode); + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setTransformationMode(transformationMode.ordinal()); + } + } + + /** + * Switch transformation type. + */ + @FxThread + private void updateTransformTool(@NotNull EditorTransformSupport.TransformType transformType, @NotNull Boolean newValue) { + + /**FIXME + if (newValue != Boolean.TRUE) { + if (editor3dPart.getTransformType() == transformType) { + if (transformType == TransformType.MOVE_TOOL) { + moveToolButton.setSelected(true); + } else if (transformType == TransformType.ROTATE_TOOL) { + rotationToolButton.setSelected(true); + } else if (transformType == TransformType.SCALE_TOOL) { + scaleToolButton.setSelected(true); + } + } + return; + } + + var editorState = getEditorState(); + editor3dPart.setTransformType(transformType); + + if (transformType == TransformType.MOVE_TOOL) { + rotationToolButton.setSelected(false); + scaleToolButton.setSelected(false); + } else if (transformType == TransformType.ROTATE_TOOL) { + moveToolButton.setSelected(false); + scaleToolButton.setSelected(false); + } else if (transformType == TransformType.SCALE_TOOL) { + rotationToolButton.setSelected(false); + moveToolButton.setSelected(false); + } + + if (editorState != null) { + editorState.setTransformationType(transformType.ordinal()); + } **/ + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + createActions(container); + + var transformModeLabel = new Label(Messages.MODEL_FILE_EDITOR_TRANSFORM_MODE + ":"); + + transformModeComboBox.getSelectionModel() + .selectedItemProperty() + .addListener((observable, oldValue, newValue) -> changeTransformMode(newValue)); + + FxUtils.addChild(container, transformModeLabel, transformModeComboBox); + } + + @FxThread + protected void createActions(@NotNull HBox container) { + + FxUtils.addChild(container, createSaveAction()); + + selectionButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SELECTION)); + selectionButton.setGraphic(new ImageView(Icons.CUBE_16)); + selectionButton.setSelected(true); + + gridButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_GRID)); + gridButton.setGraphic(new ImageView(Icons.PLANE_16)); + gridButton.setSelected(true); + + statisticsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_STATISTICS)); + statisticsButton.setGraphic(new ImageView(Icons.STATISTICS_16)); + statisticsButton.setSelected(true); + + moveToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_MOVE_TOOL + " (G)")); + moveToolButton.setGraphic(new ImageView(Icons.MOVE_16)); + moveToolButton.setSelected(true); + + rotationToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_ROTATION_TOOL + " (R)")); + rotationToolButton.setGraphic(new ImageView(Icons.ROTATION_16)); + + scaleToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SCALE_TOOL + " (S)")); + scaleToolButton.setGraphic(new ImageView(Icons.SCALE_16)); + + FxControlUtils.onSelectedChange(scaleToolButton, this::changeSelectionVisible); + FxControlUtils.onSelectedChange(gridButton, this::changeGridVisible); + FxControlUtils.onSelectedChange(statisticsButton, this::changeStatisticsVisible); + FxControlUtils.onSelectedChange(moveToolButton, selected -> updateTransformTool(EditorTransformSupport.TransformType.MOVE_TOOL, selected)); + FxControlUtils.onSelectedChange(rotationToolButton, selected -> updateTransformTool(EditorTransformSupport.TransformType.ROTATE_TOOL, selected)); + FxControlUtils.onSelectedChange(scaleToolButton, selected -> updateTransformTool(EditorTransformSupport.TransformType.SCALE_TOOL, selected)); + + DynamicIconSupport.addSupport(selectionButton, gridButton, statisticsButton, + moveToolButton, rotationToolButton, scaleToolButton); + + FxUtils.addClass(selectionButton, gridButton, statisticsButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON) + .addClass(moveToolButton, rotationToolButton, scaleToolButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + + FxUtils.addChild(container, selectionButton, gridButton, statisticsButton, + moveToolButton, rotationToolButton, scaleToolButton); + } + + @Override + @FxThread + protected void createContent(@NotNull StackPane root) { + + scriptingComponent.prefHeightProperty() + .bind(root.heightProperty()); + + super.createContent(root); + + statsContainer.setMouseTransparent(true); + statsContainer.prefHeightProperty() + .bind(editorAreaPane.heightProperty()); + + modelNodeTree.prefHeightProperty() + .bind(root.heightProperty()); + + modelPropertyEditor.prefHeightProperty() + .bind(root.heightProperty()); + + FxUtils.addChild(editorAreaPane, statsContainer); + + FxUtils.addClass(statsContainer, CssClasses.SCENE_EDITOR_STATS_CONTAINER) + .addClass(modelNodeTree.getTreeView(), CssClasses.TRANSPARENT_TREE_VIEW); + } + + @Override + @FxThread + protected void createToolComponents(@NotNull EditorToolComponent container, @NotNull StackPane root) { + super.createToolComponents(container, root); + + container.addComponent(buildSplitComponent(modelNodeTreeObjectsContainer, propertyEditorObjectsContainer, root), + Messages.SCENE_FILE_EDITOR_TOOL_OBJECTS); + container.addComponent(buildSplitComponent(modelNodeTreeEditingContainer, paintingComponentContainer, root), + Messages.SCENE_FILE_EDITOR_TOOL_PAINTING); + + container.addComponent(scriptingComponent, Messages.SCENE_FILE_EDITOR_TOOL_SCRIPTING); + } + + /** + * Refresh tree. + */ + @FxThread + protected void refreshTree() { + modelNodeTree.fill(notNull(getCurrentModel())); + } + + /** + * Process change tool. + * + * @param oldValue the old value + * @param newValue the new value + */ + @FxThread + protected void processChangeTool(@Nullable Number oldValue, @NotNull Number newValue) { + + var propertyEditorParent = (VBox) modelPropertyEditor.getParent(); + var modelNodeTreeParent = (VBox) modelNodeTree.getParent(); + + if (propertyEditorParent != null) { + FxUtils.removeChild(propertyEditorParent, modelPropertyEditor); + } + + if (modelNodeTreeParent != null) { + FxUtils.removeChild(modelNodeTreeParent, modelNodeTree); + } + + var oldIndex = oldValue == null ? -1 : oldValue.intValue(); + var newIndex = newValue.intValue(); + + if (newIndex == OBJECTS_TOOL) { + FxUtils.addChild(propertyEditorObjectsContainer, modelPropertyEditor); + FxUtils.addChild(modelNodeTreeObjectsContainer, modelNodeTree); + selectNodesFromTree(modelNodeTree.getSelectedItems()); + } else if (newIndex == PAINTING_TOOL) { + FXUtils.addToPane(modelNodeTree, modelNodeTreeEditingContainer); + paintingComponentContainer.notifyShowed(); + } + + if (oldIndex == PAINTING_TOOL) { + paintingComponentContainer.notifyHided(); + } + + //FIXME editor3dPart.changePaintingMode(newIndex == PAINTING_TOOL); + } + + @Override + @FxThread + protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { + + UiUtils.handleDroppedFile(dragEvent, this, dragEvent, FileExtensions.JME_OBJECT, + AbstractSceneFileEditor::addNewModel); + + UiUtils.handleDroppedFile(dragEvent, this, dragEvent, FileExtensions.JME_MATERIAL, + AbstractSceneFileEditor::applyMaterial); + } + + @Override + @FxThread + protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { + super.handleDragOverEvent(dragEvent); + UiUtils.acceptIfHasFile(dragEvent, ACCEPTED_FILES); + } + + /** + * Apply a new material from an asset tree. + * + * @param dragEvent the drag event. + * @param file the file. + */ + @FxThread + private void applyMaterial(@NotNull DragEvent dragEvent, @NotNull Path file) { + + var assetFile = EditorUtils.requireAssetFile(file); + var assetPath = EditorUtils.toAssetPath(assetFile); + + var materialKey = new MaterialKey(assetPath); + var camera = editor3dPart.getCamera(); + + var area = notNull(get3dArea()); + var areaPoint = area.sceneToLocal(dragEvent.getSceneX(), dragEvent.getSceneY()); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + + var geometry = editor3dPart.getGeometryByScreenPos((float) areaPoint.getX(), + camera.getHeight() - (float) areaPoint.getY()); + + if (geometry == null) { + return; + } + + var linkNode = NodeUtils.findParent(geometry, AssetLinkNode.class::isInstance); + + if (linkNode != null) { + return; + } + + var assetManager = EditorUtils.getAssetManager(); + var material = assetManager.loadAsset(materialKey); + + var operation = new PropertyOperation(geometry, + Messages.MODEL_PROPERTY_MATERIAL, material, geometry.getMaterial()); + + operation.setApplyHandler(Geometry::setMaterial); + + execute(operation); + }); + } + + /** + * Add a new model from an asset tree. + * + * @param dragEvent the drag event. + * @param file the file. + */ + @FxThread + private void addNewModel(@NotNull DragEvent dragEvent, @NotNull Path file) { + + var currentModel = getCurrentModel(); + if (!(currentModel instanceof Node)) { + return; + } + + var selected = modelNodeTree.getSelectedObject(); + + final Node parent; + + if (selected instanceof Node && + modelNodeTree.getSelectedCount() == 1 && + NodeUtils.findParent((Spatial) selected, AssetLinkNode.class::isInstance) == null) { + parent = (Node) selected; + } else { + parent = (Node) currentModel; + } + + var assetFile = EditorUtils.requireAssetFile(file); + var assetPath = EditorUtils.toAssetPath(assetFile); + + var modelKey = new ModelKey(assetPath); + var camera = editor3dPart.getCamera(); + + var area = notNull(get3dArea()); + var areaPoint = area.sceneToLocal(dragEvent.getSceneX(), dragEvent.getSceneY()); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + + var defaultLayer = EditorUtils.getDefaultLayer(this); + var local = LocalObjects.get(); + + var loadedModel = EditorUtils.getAssetManager() + .loadModel(modelKey); + + var assetLinkNode = new AssetLinkNode(modelKey); + assetLinkNode.attachLinkedChild(loadedModel, modelKey); + assetLinkNode.setUserData(AbstractSceneEditor3dPart.KEY_LOADED_MODEL, true); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, assetLinkNode); + } + + var scenePoint = editor3dPart.getScenePosByScreenPos((float) areaPoint.getX(), + camera.getHeight() - (float) areaPoint.getY()); + var result = local.nextVector(scenePoint) + .subtractLocal(parent.getWorldTranslation()); + + var isPhysics = NodeUtils.children(loadedModel) + .flatMap(ControlUtils::controls) + .anyMatch(PhysicsControl.class::isInstance); + + if (isPhysics) { + + NodeUtils.updateWorldBound(loadedModel); + + var worldBound = loadedModel.getWorldBound(); + + float height = 0; + + if (worldBound instanceof BoundingBox) { + height = ((BoundingBox) worldBound).getYExtent(); + height = Math.min(((BoundingBox) worldBound).getXExtent(), height); + height = Math.min(((BoundingBox) worldBound).getZExtent(), height); + } else if (worldBound instanceof BoundingSphere) { + height = ((BoundingSphere) worldBound).getRadius(); + } + + height /= 2F; + + var localRotation = assetLinkNode.getLocalRotation(); + var up = GeomUtils.getUp(localRotation, local.nextVector()); + up.multLocal(height); + + result.addLocal(up); + } + + + assetLinkNode.setLocalTranslation(result); + + execute(new AddChildOperation(assetLinkNode, parent, false)); + }); + } + + + /** + * Handle changing select visibility. + */ + @FxThread + private void changeSelectionVisible(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + //FIXME editor3dPart.updateShowSelection(newValue); + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setEnableSelection(newValue); + } + } + + /** + * Handle changing grid visibility. + */ + @FxThread + private void changeGridVisible(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + editor3dPart.updateShowGrid(newValue); + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setEnableGrid(newValue); + } + } + + /** + * Handle changing statistics visibility. + */ + @FxThread + private void changeStatisticsVisible(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + stats3dPart.setEnabled(newValue); + + var editorState = getEditorState(); + if (editorState != null) { + editorState.setShowStatistics(newValue); + } + } + + /** + * Notify about transformed the object. + * + * @param spatial the spatial + */ + @FromAnyThread + public void notifyTransformed(@NotNull Spatial spatial) { + ExecutorManager.getInstance() + .addFxTask(() -> notifyTransformedImpl(spatial)); + } + + /** + * Notify about transformed the object. + */ + @FxThread + private void notifyTransformedImpl(@NotNull Spatial spatial) { + + Object toUpdate = spatial; + + if (spatial instanceof WrapperNode) { + toUpdate = ((WrapperNode) spatial).getWrappedObject(); + } + + modelPropertyEditor.syncFor(toUpdate); + } + + @Override + @JmeThread + public @NotNull Node getCursorNode() { + //FIXME return editor3dPart.getCursorNode(); + return null; + } + + @Override + @JmeThread + public @NotNull Node getMarkersNode() { + //return editor3dPart.getMarkersNode(); + //FIXME + return null; + } +} + diff --git a/src/main/java/com/ss/builder/editor/impl/scene/SceneFileEditor.java b/src/main/java/com/ss/builder/editor/impl/scene/SceneFileEditor.java new file mode 100644 index 00000000..8bc8b91e --- /dev/null +++ b/src/main/java/com/ss/builder/editor/impl/scene/SceneFileEditor.java @@ -0,0 +1,610 @@ +package com.ss.builder.editor.impl.scene; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.ModelKey; +import com.jme3.scene.Spatial; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.scene.SceneEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.RenameNodeOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.editor.state.EditorState; +import com.ss.builder.editor.state.impl.EditorSceneEditorState; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialUtils; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.ScenePresentable; +import com.ss.editor.extension.scene.app.state.EditableSceneAppState; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.editor.extension.scene.filter.EditableSceneFilter; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.impl.AbstractFileEditorLegacy; +import com.ss.builder.fx.component.tab.EditorToolComponent; +import com.ss.builder.fx.control.app.state.list.AppStateList; +import com.ss.builder.fx.control.filter.list.FilterList; +import com.ss.builder.fx.control.layer.LayerNodeTree; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * The implementation of the {@link AbstractFileEditorLegacy} for working with {@link SceneNode}. + * + * @author JavaSaBr + */ +public class SceneFileEditor extends AbstractSceneFileEditor + implements SceneChangeConsumer { + + public static final EditorDescriptor DESCRIPTOR = new EditorDescriptor( + SceneFileEditor::new, + Messages.SCENE_FILE_EDITOR_NAME, + SceneFileEditor.class.getSimpleName(), + FileExtensions.JME_SCENE + ); + + private static final int LAYERS_TOOL = 3; + private static final int APP_STATES_TOOL = 4; + private static final int FILTERS_TOOL = 5; + + /** + * The list with app states. + */ + @NotNull + private final AppStateList appStateList; + + /** + * The list with filters. + */ + @NotNull + private final FilterList filterList; + + /** + * The tree with layers. + */ + @NotNull + private final LayerNodeTree layerNodeTree; + + /** + * The light toggle. + */ + @NotNull + private final ToggleButton lightButton; + + /** + * The audio toggle. + */ + @NotNull + private final ToggleButton audioButton; + + /** + * The container of property editor in app states tool. + */ + @NotNull + private final VBox propertyEditorAppStateContainer; + + /** + * The container of property editor in filters tool. + */ + @NotNull + private final VBox propertyEditorFiltersContainer; + + /** + * The container of property editor in layers tool. + */ + @NotNull + private final VBox propertyEditorLayersContainer; + + /** + * The flag of sync selection. + */ + private boolean needSyncSelection; + + private SceneFileEditor() { + setNeedSyncSelection(true); + this.lightButton = new ToggleButton(); + this.audioButton = new ToggleButton(); + this.appStateList = new AppStateList(this::selectAppStateFromList, this); + this.filterList = new FilterList(this::selectFilterFromList, this); + this.layerNodeTree = new LayerNodeTree(this::selectNodeFromLayersTree, this); + this.propertyEditorAppStateContainer = new VBox(); + this.propertyEditorFiltersContainer = new VBox(); + this.propertyEditorLayersContainer = new VBox(); + } + + @Override + @FxThread + protected @NotNull SceneEditor3dPart create3dEditorPart() { + return new SceneEditor3dPart(this); + } + + @Override + @FxThread + protected @Nullable Supplier getEditorStateFactory() { + return EditorSceneEditorState::new; + } + + @Override + @BackgroundThread + protected void doOpenFile(@NotNull Path file) throws IOException { + super.doOpenFile(file); + + var assetFile = EditorUtils.requireAssetFile(file); + var modelKey = new ModelKey(EditorUtils.toAssetPath(assetFile)); + + Spatial loadedScene = EditorUtils.getAssetManager() + .loadAsset(modelKey); + + var model = (SceneNode) loadedScene; + model.depthFirstTraversal(this::updateVisibility); + + MaterialUtils.cleanUpMaterialParams(model); + + editor3dPart.openModel(model); + handleAddedObject(model); + setCurrentModel(model); + setIgnoreListeners(true); + try { + refreshTree(); + } finally { + setIgnoreListeners(false); + } + } + + @Override + @FxThread + protected void refreshTree() { + super.refreshTree(); + + var model = getCurrentModel(); + + appStateList.fill(model); + filterList.fill(model); + layerNodeTree.fill(new LayersRoot(this)); + } + + @FxThread + private void updateVisibility(@NotNull Spatial spatial) { + var layer = SceneLayer.getLayer(spatial); + if (layer != null) { + spatial.setVisible(layer.isShowed()); + } + } + + @Override + @FxThread + protected boolean isNeedToOpenObjectsTool(int current) { + return !(current == OBJECTS_TOOL || current == LAYERS_TOOL || current == SCRIPTING_TOOL); + } + + @Override + @FxThread + protected void createToolbar(@NotNull final HBox container) { + super.createToolbar(container); + + lightButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SHOW_LIGHTS)); + lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); + lightButton.setSelected(true); + + audioButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SHOW_AUDIO)); + audioButton.setGraphic(new ImageView(Icons.AUDIO_16)); + audioButton.setSelected(true); + + FxControlUtils.onSelectedChange(lightButton, this::changeLight); + FxControlUtils.onSelectedChange(audioButton, this::changeAudio); + + DynamicIconSupport.addSupport(lightButton, audioButton); + + FxUtils.addClass(lightButton, audioButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + FxUtils.addChild(container, lightButton, audioButton); + } + + /** + * Handle changing light models visibility. + */ + @FxThread + private void changeLight(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + editor3dPart.updateLightShowed(newValue); + + if (editorState != null) { + editorState.setShowedLight(newValue); + } + } + + /** + * Handle changing audio models visibility. + */ + @FxThread + private void changeAudio(@NotNull Boolean newValue) { + + if (isIgnoreListeners()) { + return; + } + + editor3dPart.updateAudioShowed(newValue); + + if (editorState != null) { + editorState.setShowedAudio(newValue); + } + } + + @Override + @FxThread + protected void createContent(@NotNull StackPane root) { + super.createContent(root); + + FxUtils.addClass(layerNodeTree.getTreeView(), + CssClasses.TRANSPARENT_TREE_VIEW); + } + + @Override + @FxThread + protected void createToolComponents(@NotNull EditorToolComponent container, @NotNull StackPane root) { + super.createToolComponents(container, root); + + container.addComponent(buildSplitComponent(layerNodeTree, propertyEditorLayersContainer, root), + Messages.SCENE_FILE_EDITOR_TOOL_LAYERS); + container.addComponent(buildSplitComponent(appStateList, propertyEditorAppStateContainer, root), + Messages.SCENE_FILE_EDITOR_TOOL_APP_STATES); + container.addComponent(buildSplitComponent(filterList, propertyEditorFiltersContainer, root), + Messages.SCENE_FILE_EDITOR_TOOL_FILTERS); + } + + @Override + @FxThread + protected void processChangeTool(@Nullable Number oldValue, @NotNull Number newValue) { + super.processChangeTool(oldValue, newValue); + + var newIndex = newValue.intValue(); + if (newIndex < 2) { + return; + } + + switch (newIndex) { + case LAYERS_TOOL: { + var selected = layerNodeTree.getSelected(); + FxUtils.addChild(propertyEditorLayersContainer, modelPropertyEditor); + selectNodeFromLayersTree(selected); + break; + } + case APP_STATES_TOOL: { + FxUtils.addChild(propertyEditorAppStateContainer, modelPropertyEditor); + selectAppStateFromList(appStateList.getSelected()); + break; + } + case FILTERS_TOOL: { + FxUtils.addChild(propertyEditorFiltersContainer, modelPropertyEditor); + selectFilterFromList(filterList.getSelected()); + break; + } + } + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + var editorState = notNull(getEditorState()); + + lightButton.setSelected(editorState.isShowedLight()); + audioButton.setSelected(editorState.isShowedAudio()); + } + + /** + * Handle the selected app state from the list. + */ + @FxThread + private void selectAppStateFromList(@Nullable EditableSceneAppState appState) { + + if (!isNeedSyncSelection()) { + return; + } + + setNeedSyncSelection(false); + try { + super.selectNodeFromTree(appState); + } finally { + setNeedSyncSelection(true); + } + } + + /** + * Handle the selected filter from the list. + */ + @FxThread + private void selectFilterFromList(@Nullable EditableSceneFilter sceneFilter) { + + if (!isNeedSyncSelection()) { + return; + } + + setNeedSyncSelection(false); + try { + super.selectNodeFromTree(sceneFilter); + } finally { + setNeedSyncSelection(true); + } + } + + /** + * Handle the selected object from the layers tree. + */ + @FxThread + private void selectNodeFromLayersTree(@Nullable Object object) { + + if (!isNeedSyncSelection()) { + return; + } + + setNeedSyncSelection(false); + try { + modelNodeTree.selectSingle(object); + selectNodeFromTree(object); + } finally { + setNeedSyncSelection(true); + } + } + + @Override + @FxThread + public void selectNodesFromTree(@NotNull Array objects) { + + if (!isNeedSyncSelection()) { + super.selectNodesFromTree(objects); + return; + } + + setNeedSyncSelection(false); + try { + layerNodeTree.selects(objects); + super.selectNodesFromTree(objects); + } finally { + setNeedSyncSelection(true); + } + } + + @Override + @FromAnyThread + public @NotNull EditorDescriptor getDescriptor() { + return DESCRIPTOR; + } + + /** + * Return true if need sync selection. + * + * @param needSyncSelection true if need sync selection. + */ + @FxThread + private void setNeedSyncSelection(boolean needSyncSelection) { + this.needSyncSelection = needSyncSelection; + } + + /** + * Return true if need sync selection. + * + * @return true if need sync selection. + */ + @FxThread + private boolean isNeedSyncSelection() { + return needSyncSelection; + } + + @Override + protected boolean canSelect(@NotNull Spatial spatial) { + return !(spatial instanceof SceneNode) && !(spatial instanceof SceneLayer) && super.canSelect(spatial); + } + + @Override + @FxThread + protected void handleAddedObject(@NotNull Spatial model) { + super.handleAddedObject(model); + + if (!(model instanceof SceneNode)) { + return; + } + + var sceneNode = (SceneNode) model; + + sceneNode.getFilters().stream() + .filter(ScenePresentable.class::isInstance) + .forEach(filter -> editor3dPart.addPresentable((ScenePresentable) filter)); + sceneNode.getAppStates().stream() + .filter(ScenePresentable.class::isInstance) + .forEach(state -> editor3dPart.addPresentable((ScenePresentable) state)); + } + + @Override + @FxThread + protected void handleRemovedObject(@NotNull Spatial model) { + super.handleRemovedObject(model); + + if (!(model instanceof SceneNode)) { + return; + } + + var sceneNode = (SceneNode) model; + + sceneNode.getFilters().stream() + .filter(ScenePresentable.class::isInstance) + .forEach(filter -> editor3dPart.removePresentable((ScenePresentable) filter)); + sceneNode.getAppStates().stream() + .filter(ScenePresentable.class::isInstance) + .forEach(state -> editor3dPart.removePresentable((ScenePresentable) state)); + } + + @Override + @FxThread + public void notifyFxAddedChild(@NotNull Object parent, @NotNull Object added, int index, boolean needSelect) { + super.notifyFxAddedChild(parent, added, index, needSelect); + + if (parent instanceof LayersRoot) { + layerNodeTree.notifyAdded(parent, added, index); + } else if (added instanceof Spatial) { + layerNodeTree.notifyAdded((Spatial) added); + } + + ExecutorManager.getInstance() + .addJmeTask(() -> getCurrentModel().notifyAdded(added)); + } + + @Override + @FxThread + public void notifyFxRemovedChild(@NotNull Object parent, @NotNull Object removed) { + super.notifyFxRemovedChild(parent, removed); + + if (parent instanceof LayersRoot) { + layerNodeTree.notifyRemoved(parent, removed); + } else if (removed instanceof Spatial) { + layerNodeTree.notifyRemoved((Spatial) removed); + } + + ExecutorManager.getInstance() + .addJmeTask(() -> getCurrentModel().notifyRemoved(removed)); + } + + @Override + @FxThread + public void notifyFxChangeProperty(@Nullable Object parent, @NotNull Object object, @NotNull String propertyName) { + super.notifyFxChangeProperty(parent, object, propertyName); + + if (object instanceof EditableProperty) { + object = ((EditableProperty) object).getObject(); + } + + if (object instanceof Spatial && Objects.equals(propertyName, Messages.MODEL_PROPERTY_LAYER)) { + + var spatial = (Spatial) object; + var layer = SceneLayer.getLayer(spatial); + + if (layer == null) { + spatial.setVisible(true); + } else { + spatial.setVisible(layer.isShowed()); + } + + layerNodeTree.notifyChangedLayer(spatial, layer); + } + + if (object instanceof EditableSceneAppState && RenameNodeOperation.PROPERTY_NAME.equals(propertyName)) { + appStateList.refresh((EditableSceneAppState) object); + } + + layerNodeTree.notifyChanged(null, object); + } + + @Override + @FxThread + public void notifyAddedAppState(@NotNull SceneAppState appState) { + + editor3dPart.addAppState(appState); + + if (appState instanceof ScenePresentable) { + editor3dPart.addPresentable((ScenePresentable) appState); + } + + appStateList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyRemovedAppState(@NotNull SceneAppState appState) { + + editor3dPart.removeAppState(appState); + + if (appState instanceof ScenePresentable) { + editor3dPart.removePresentable((ScenePresentable) appState); + } + + appStateList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyChangedAppState(@NotNull SceneAppState appState) { + appStateList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyAddedFilter(@NotNull SceneFilter sceneFilter) { + + editor3dPart.addFilter(sceneFilter); + + if (sceneFilter instanceof ScenePresentable) { + editor3dPart.addPresentable((ScenePresentable) sceneFilter); + } + + filterList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyRemovedFilter(@NotNull SceneFilter sceneFilter) { + + editor3dPart.removeFilter(sceneFilter); + + if (sceneFilter instanceof ScenePresentable) { + editor3dPart.removePresentable((ScenePresentable) sceneFilter); + } + + filterList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyChangedFilter(@NotNull SceneFilter sceneFilter) { + filterList.fill(getCurrentModel()); + } + + @Override + @FxThread + public void notifyHide() { + super.notifyHide(); + + ExecutorManager.getInstance() + .addJmeTask(EditorUtils::enableGlobalLightProbe); + } + + @Override + @FxThread + public void notifyShowed() { + super.notifyShowed(); + + ExecutorManager.getInstance() + .addJmeTask(EditorUtils::disableGlobalLightProbe); + } + + @Override + public String toString() { + return "SceneFileEditor{} " + super.toString(); + } +} diff --git a/src/main/java/com/ss/builder/editor/state/EditorState.java b/src/main/java/com/ss/builder/editor/state/EditorState.java new file mode 100644 index 00000000..bc643e2a --- /dev/null +++ b/src/main/java/com/ss/builder/editor/state/EditorState.java @@ -0,0 +1,48 @@ +package com.ss.builder.editor.state; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.event.FileEditorEvent; +import com.ss.builder.editor.state.impl.AdditionalEditorState; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.function.Supplier; + +/** + * The interface for implementing a state container of Editor. + * + * @author JavaSaBr + */ +public interface EditorState extends Serializable { + + /** + * Sets change handler. + * + * @param handle the change handler. + */ + @FxThread + void setChangeHandler(@NotNull Runnable handle); + + /** + * Get or create an additional editor state which will store state in this state. + * + * @param type the type of additional state. + * @param factory the factory of the state if it will not be exists. + * @param the type of the state. + * @return the additional editor state. + */ + @FxThread + @NotNull T getOrCreateAdditionalState( + @NotNull Class type, + @NotNull Supplier factory + ); + + /** + * Notify this editor's state about some editor's events. + * + * @param event the file editor's state. + */ + @FxThread + default void notify(@NotNull FileEditorEvent event) { + } +} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/EditorToolConfig.java b/src/main/java/com/ss/builder/editor/state/EditorToolConfig.java similarity index 88% rename from src/main/java/com/ss/editor/ui/component/editor/state/EditorToolConfig.java rename to src/main/java/com/ss/builder/editor/state/EditorToolConfig.java index 12007c24..a8cde029 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/EditorToolConfig.java +++ b/src/main/java/com/ss/builder/editor/state/EditorToolConfig.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui.component.editor.state; +package com.ss.builder.editor.state; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; /** * The interface implementing a state of editor tool. diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/AbstractEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/AbstractEditorState.java similarity index 93% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/AbstractEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/AbstractEditorState.java index a84bdccb..6a349de7 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/AbstractEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/AbstractEditorState.java @@ -1,9 +1,9 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.editor.state.EditorState; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.editor.state.EditorState; import com.ss.rlib.common.util.ArrayUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/editor/state/impl/AdditionalEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/AdditionalEditorState.java new file mode 100644 index 00000000..08d70b7f --- /dev/null +++ b/src/main/java/com/ss/builder/editor/state/impl/AdditionalEditorState.java @@ -0,0 +1,11 @@ +package com.ss.builder.editor.state.impl; + +import com.ss.builder.editor.state.EditorState; + +/** + * The interface to implement additional state of an editor. + * + * @author JavaSaBr + */ +public interface AdditionalEditorState extends EditorState { +} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/BaseEditorSceneEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/BaseEditorSceneEditorState.java similarity index 88% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/BaseEditorSceneEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/BaseEditorSceneEditorState.java index 01c27efb..f4072a05 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/BaseEditorSceneEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/BaseEditorSceneEditorState.java @@ -1,16 +1,15 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.control.transform.EditorTransformSupport.TransformType; -import com.ss.editor.control.transform.EditorTransformSupport.TransformationMode; -import com.ss.editor.ui.component.editor.impl.scene.AbstractSceneFileEditor; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.impl.scene.AbstractSceneFileEditor; +import com.ss.builder.jme.control.transform.EditorTransformSupport; /** * The base implementation of a state container for the {@link AbstractSceneFileEditor}. * * @author JavaSaBr */ -public abstract class BaseEditorSceneEditorState extends Editor3DWithEditorToolEditorState { +public abstract class BaseEditorSceneEditorState extends Editor3dWithEditorToolEditorState { /** * The constant serialVersionUID. @@ -45,8 +44,8 @@ public abstract class BaseEditorSceneEditorState extends Editor3DWithEditorToolE public BaseEditorSceneEditorState() { this.enableGrid = true; this.enableSelection = true; - this.transformationMode = TransformationMode.GLOBAL.ordinal(); - this.transformationType = TransformType.MOVE_TOOL.ordinal(); + this.transformationMode = EditorTransformSupport.TransformationMode.GLOBAL.ordinal(); + this.transformationType = EditorTransformSupport.TransformType.MOVE_TOOL.ordinal(); } /** diff --git a/src/main/java/com/ss/builder/editor/state/impl/Editor3dEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/Editor3dEditorState.java new file mode 100644 index 00000000..75a1a6e2 --- /dev/null +++ b/src/main/java/com/ss/builder/editor/state/impl/Editor3dEditorState.java @@ -0,0 +1,195 @@ +package com.ss.builder.editor.state.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.event.CameraChangedFileEditorEvent; +import com.ss.builder.editor.event.FileEditorEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * The base implementation of a state container for an 3D editor. + * + * @author JavaSaBr + */ +public class Editor3dEditorState extends AbstractEditorState { + + /** + * The constant serialVersionUID. + */ + public static final long serialVersionUID = 2; + + /** + * The camera location. + */ + @Nullable + protected volatile Vector3f cameraLocation; + + /** + * The vertical camera rotation. + */ + protected volatile float cameraVRotation; + + /** + * The horizontal camera rotation. + */ + protected volatile float cameraHRotation; + + /** + * The camera speed. + */ + protected volatile float cameraFlySpeed; + + /** + * The camera zoom. + */ + protected volatile float cameraTargetDistance; + + public Editor3dEditorState() { + this.cameraLocation = new Vector3f(); + this.cameraVRotation = FastMath.PI / 6; + this.cameraTargetDistance = 20; + this.cameraHRotation = 0; + this.cameraFlySpeed = 1; + } + + @Override + @FxThread + public void notify(@NotNull FileEditorEvent event) { + if (event instanceof CameraChangedFileEditorEvent) { + var state = ((CameraChangedFileEditorEvent) event).getCameraState(); + setCameraLocation(state.getCameraLocation()); + setCameraHRotation(state.getHRotation()); + setCameraVRotation(state.getVRotation()); + setCameraFlySpeed(state.getCameraFlySpeed()); + setCameraTargetDistance(state.getTargetDistance()); + } + } + + /** + * Set the horizontal camera rotation. + * + * @param cameraHRotation the new horizontal rotation. + */ + @FxThread + public void setCameraHRotation(float cameraHRotation) { + var changed = getCameraHRotation() != cameraHRotation; + this.cameraHRotation = cameraHRotation; + if (changed) notifyChange(); + } + + /** + * Get the horizontal camera rotation. + * + * @return the horizontal camera rotation. + */ + @FromAnyThread + public float getCameraHRotation() { + return cameraHRotation; + } + + /** + * Set the new camera position. + * + * @param cameraLocation the new camera position. + */ + @FxThread + public void setCameraLocation(@NotNull Vector3f cameraLocation) { + var changed = Objects.equals(getCameraLocation(), cameraLocation); + getCameraLocation().set(cameraLocation); + if (changed) notifyChange(); + } + + /** + * Get the camera location. + * + * @return the camera location. + */ + @FromAnyThread + public @NotNull Vector3f getCameraLocation() { + + if (cameraLocation == null) { + cameraLocation = new Vector3f(); + } + + return notNull(cameraLocation); + } + + /** + * Set the new camera target distance. + * + * @param cameraTargetDistance the new camera target distance. + */ + @FxThread + public void setCameraTargetDistance(float cameraTargetDistance) { + var changed = getCameraTargetDistance() != cameraTargetDistance; + this.cameraTargetDistance = cameraTargetDistance; + if (changed) notifyChange(); + } + + /** + * Get the camera target distance. + * + * @return the camera target distance. + */ + @FromAnyThread + public float getCameraTargetDistance() { + return cameraTargetDistance; + } + + /** + * Set the camera fly speed. + * + * @param cameraFlySpeed the camera fly speed. + */ + @FxThread + public void setCameraFlySpeed(float cameraFlySpeed) { + var changed = getCameraFlySpeed() != cameraFlySpeed; + this.cameraFlySpeed = cameraFlySpeed; + if (changed) notifyChange(); + } + + /** + * Get the camera fly speed. + * + * @return the camera fly speed. + */ + @FromAnyThread + public float getCameraFlySpeed() { + return cameraFlySpeed; + } + + /** + * Set the new vertical camera rotation. + * + * @param cameraVRotation the new vertical camera rotation. + */ + @FxThread + public void setCameraVRotation(float cameraVRotation) { + var changed = getCameraVRotation() != cameraVRotation; + this.cameraVRotation = cameraVRotation; + if (changed) notifyChange(); + } + + /** + * Get the camera vertical rotation. + * + * @return the camera vertical rotation. + */ + @FromAnyThread + public float getCameraVRotation() { + return cameraVRotation; + } + + @Override + public String toString() { + return "Editor3DEditorState{" + "cameraLocation=" + cameraLocation + ", cameraVRotation=" + cameraVRotation + + ", cameraHRotation=" + cameraHRotation + ", cameraFlySpeed=" + cameraFlySpeed + ", cameraTargetDistance=" + + cameraTargetDistance + '}'; + } +} diff --git a/src/main/java/com/ss/builder/editor/state/impl/Editor3dWithEditorToolEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/Editor3dWithEditorToolEditorState.java new file mode 100644 index 00000000..740cb9ec --- /dev/null +++ b/src/main/java/com/ss/builder/editor/state/impl/Editor3dWithEditorToolEditorState.java @@ -0,0 +1,100 @@ +package com.ss.builder.editor.state.impl; + +import static java.lang.Math.abs; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.state.EditorToolConfig; + +/** + * The base implementation of a state container for an 3D editor with editor tool. + * + * @author JavaSaBr + */ +public class Editor3dWithEditorToolEditorState extends Editor3dEditorState implements EditorToolConfig { + + /** + * The constant serialVersionUID. + */ + public static final long serialVersionUID = 1; + + /** + * The width of tool split panel. + */ + protected volatile int toolWidth; + + /** + * The flag of collapsing split panel. + */ + protected volatile boolean toolCollapsed; + + /** + * Opened editor tool. + */ + private volatile int openedTool; + + /** + * Instantiates a new Abstract editor state. + */ + public Editor3dWithEditorToolEditorState() { + this.toolWidth = 250; + this.toolCollapsed = false; + openedTool = 0; + } + + @Override + @FxThread + public int getToolWidth() { + return toolWidth; + } + + @Override + @FxThread + public void setToolWidth(final int toolWidth) { + final boolean changed = abs(getToolWidth() - toolWidth) > 3; + this.toolWidth = toolWidth; + if (changed) notifyChange(); + } + + @Override + @FxThread + public boolean isToolCollapsed() { + return toolCollapsed; + } + + @Override + @FxThread + public void setToolCollapsed(final boolean toolCollapsed) { + final boolean changed = isToolCollapsed() != toolCollapsed; + this.toolCollapsed = toolCollapsed; + if (changed) notifyChange(); + } + + /** + * Gets opened tool. + * + * @return the opened tool. + */ + public int getOpenedTool() { + return openedTool; + } + + /** + * Sets opened tool. + * + * @param openedTool the opened tool. + */ + public void setOpenedTool(final int openedTool) { + final boolean changed = getOpenedTool() != openedTool; + this.openedTool = openedTool; + final Runnable changeHandler = getChangeHandler(); + if (changed && changeHandler != null) { + changeHandler.run(); + } + } + + @Override + public String toString() { + return "Editor3DWithEditorToolEditorState{" + "toolWidth=" + toolWidth + ", toolCollapsed=" + toolCollapsed + + ", cameraLocation=" + cameraLocation + ", cameraVRotation=" + cameraVRotation + ", cameraHRotation=" + + cameraHRotation + ", cameraFlySpeed=" + cameraFlySpeed + ", cameraTargetDistance=" + cameraTargetDistance + '}'; + } +} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorMaterialEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/EditorMaterialEditorState.java similarity index 81% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorMaterialEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/EditorMaterialEditorState.java index 0420faa3..cc25e0c5 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorMaterialEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/EditorMaterialEditorState.java @@ -1,11 +1,10 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_CAMERA_LAMP; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_CAMERA_LIGHT; import com.jme3.renderer.queue.RenderQueue; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.editor.material.BaseMaterialEditor3DPart; -import com.ss.editor.ui.component.editor.impl.material.MaterialFileEditor; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart; +import com.ss.builder.editor.impl.material.MaterialFileEditor; import org.jetbrains.annotations.NotNull; @@ -14,7 +13,7 @@ * * @author JavaSaBr */ -public class EditorMaterialEditorState extends Editor3DWithEditorToolEditorState { +public class EditorMaterialEditorState extends Editor3dWithEditorToolEditorState { /** * The constant serialVersionUID. @@ -40,9 +39,9 @@ public class EditorMaterialEditorState extends Editor3DWithEditorToolEditorState private volatile boolean lightEnable; public EditorMaterialEditorState() { - modelType = BaseMaterialEditor3DPart.ModelType.BOX.ordinal(); + modelType = BaseMaterialEditor3dPart.ModelType.BOX.ordinal(); bucketTypeId = RenderQueue.Bucket.Inherit.ordinal(); - lightEnable = EDITOR_CONFIG.getBoolean(PREF_CAMERA_LAMP, PREF_DEFAULT_CAMERA_LIGHT); + lightEnable = EDITOR_CONFIG.getBoolean(DefaultSettingsProvider.Preferences.PREF_CAMERA_LAMP, DefaultSettingsProvider.Defaults.PREF_DEFAULT_CAMERA_LIGHT); } /** @@ -96,7 +95,7 @@ public int getModelType() { * @param modelType the model type. */ @FxThread - public void setModelType(@NotNull final BaseMaterialEditor3DPart.ModelType modelType) { + public void setModelType(@NotNull final BaseMaterialEditor3dPart.ModelType modelType) { final boolean changed = getModelType() != modelType.ordinal(); this.modelType = modelType.ordinal(); final Runnable changeHandler = getChangeHandler(); diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorModelEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/EditorModelEditorState.java similarity index 86% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorModelEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/EditorModelEditorState.java index ede7a9d8..404a8158 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorModelEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/EditorModelEditorState.java @@ -1,9 +1,8 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_CAMERA_LAMP; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_CAMERA_LIGHT; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.impl.model.ModelFileEditor; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.editor.impl.model.ModelFileEditor; /** * The implementation of a state container for the {@link ModelFileEditor}. @@ -39,7 +38,7 @@ public class EditorModelEditorState extends BaseEditorSceneEditorState { public EditorModelEditorState() { this.skyType = 0; - this.enableLight = EDITOR_CONFIG.getBoolean(PREF_CAMERA_LAMP, PREF_DEFAULT_CAMERA_LIGHT); + this.enableLight = EDITOR_CONFIG.getBoolean(DefaultSettingsProvider.Preferences.PREF_CAMERA_LAMP, DefaultSettingsProvider.Defaults.PREF_DEFAULT_CAMERA_LIGHT); this.enablePhysics = false; this.enableDebugPhysics = false; } diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorSceneEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/EditorSceneEditorState.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorSceneEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/EditorSceneEditorState.java index b896a0a3..6c32c786 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorSceneEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/EditorSceneEditorState.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.impl.scene.SceneFileEditor; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.impl.scene.SceneFileEditor; /** * The implementation of a state container for the {@link SceneFileEditor}. diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorWithEditorToolEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/EditorWithEditorToolEditorState.java similarity index 87% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorWithEditorToolEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/EditorWithEditorToolEditorState.java index 7b70d4c7..6c02d421 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/EditorWithEditorToolEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/EditorWithEditorToolEditorState.java @@ -1,11 +1,12 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; import static java.lang.Math.abs; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.EditorToolConfig; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.editor.BaseFileEditorWithRightTool; +import com.ss.builder.editor.state.EditorToolConfig; /** - * The base implementation of state for {@link com.ss.editor.plugin.api.editor.BaseFileEditorWithRightTool}. + * The base implementation of state for {@link BaseFileEditorWithRightTool}. * * @author JavaSaBr */ diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/VoidEditorState.java b/src/main/java/com/ss/builder/editor/state/impl/VoidEditorState.java similarity index 83% rename from src/main/java/com/ss/editor/ui/component/editor/state/impl/VoidEditorState.java rename to src/main/java/com/ss/builder/editor/state/impl/VoidEditorState.java index 04e28dbd..42f266f5 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/VoidEditorState.java +++ b/src/main/java/com/ss/builder/editor/state/impl/VoidEditorState.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.component.editor.state.impl; +package com.ss.builder.editor.state.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.EditorState; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.state.EditorState; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; diff --git a/src/main/java/com/ss/builder/executor/EditorTaskExecutor.java b/src/main/java/com/ss/builder/executor/EditorTaskExecutor.java new file mode 100644 index 00000000..82653277 --- /dev/null +++ b/src/main/java/com/ss/builder/executor/EditorTaskExecutor.java @@ -0,0 +1,24 @@ +package com.ss.builder.executor; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Executor; + +/** + * The interface to implement a task executor. + * + * @author JavaSaBr + */ +public interface EditorTaskExecutor extends Executor { + + /** + * Add the new task. + * + * @param task the new task. + */ + @Override + @FromAnyThread + void execute(@NotNull Runnable task); +} diff --git a/src/main/java/com/ss/builder/executor/impl/AbstractEditorTaskExecutor.java b/src/main/java/com/ss/builder/executor/impl/AbstractEditorTaskExecutor.java new file mode 100644 index 00000000..f5ba8880 --- /dev/null +++ b/src/main/java/com/ss/builder/executor/impl/AbstractEditorTaskExecutor.java @@ -0,0 +1,119 @@ +package com.ss.builder.executor.impl; + +import com.ss.builder.EditorThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.executor.EditorTaskExecutor; +import com.ss.rlib.common.concurrent.util.ConcurrentUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The base implementation of the {@link JmeThreadExecutor}. + * + * @author JavaSaBr + */ +public abstract class AbstractEditorTaskExecutor extends EditorThread implements EditorTaskExecutor { + + protected static final Logger LOGGER = LoggerManager.getLogger(EditorTaskExecutor.class); + + /** + * The task list to execute for each iteration. + */ + @NotNull + protected final Array execute; + + /** + * The array of executed task of the iteration. + */ + @NotNull + protected final Array executed; + + /** + * The array of task to execute. + */ + @NotNull + protected final Array waitTasks; + + /** + * Is this executor waiting new tasks. + */ + @NotNull + protected final AtomicBoolean wait; + + public AbstractEditorTaskExecutor() { + this.execute = createExecuteArray(); + this.executed = createExecuteArray(); + this.waitTasks = createExecuteArray(); + this.wait = new AtomicBoolean(false); + } + + /** + * Create a new execute tasks array. + * + * @return the new execute tasks array. + */ + @FromAnyThread + private @NotNull Array createExecuteArray() { + return Array.ofType(Runnable.class); + } + + @Override + @FromAnyThread + public void execute(@NotNull Runnable task) { + + synchronized (waitTasks) { + waitTasks.add(task); + } + + if (wait.compareAndSet(true, false)) { + ConcurrentUtils.notifyAll(wait); + } + } + + /** + * Execute the array of tasks. + * + * @param execute the execute + * @param executed the executed + */ + protected abstract void doExecute(@NotNull Array execute, @NotNull Array executed); + + @Override + public void run() { + while (true) { + + executed.clear(); + execute.clear(); + + synchronized (waitTasks) { + execute.addAll(waitTasks); + } + + if (execute.isEmpty() && wait.compareAndSet(false, true)) { + synchronized (wait) { + if (wait.get()) { + ConcurrentUtils.waitInSynchronize(wait); + } + } + } + + if (execute.isEmpty()) { + continue; + } + + doExecute(execute, executed); + + if (executed.isEmpty()) { + continue; + } + + synchronized (waitTasks) { + waitTasks.removeAll(executed); + } + } + } +} diff --git a/src/main/java/com/ss/editor/executor/impl/FxEditorTaskExecutor.java b/src/main/java/com/ss/builder/executor/impl/FxEditorTaskExecutor.java similarity index 79% rename from src/main/java/com/ss/editor/executor/impl/FxEditorTaskExecutor.java rename to src/main/java/com/ss/builder/executor/impl/FxEditorTaskExecutor.java index 4ea7adbc..fe7f0ee4 100644 --- a/src/main/java/com/ss/editor/executor/impl/FxEditorTaskExecutor.java +++ b/src/main/java/com/ss/builder/executor/impl/FxEditorTaskExecutor.java @@ -1,8 +1,8 @@ -package com.ss.editor.executor.impl; +package com.ss.builder.executor.impl; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.concurrent.util.ConcurrentUtils; import com.ss.rlib.common.util.array.Array; import javafx.application.Platform; @@ -48,7 +48,7 @@ protected void doExecute(@NotNull Array execute, @NotNull Array waitTasks; + + /** + * The list with tasks to execute. + */ + @NotNull + private final Array execute; + + private JmeThreadExecutor() { + this.waitTasks = ArrayFactory.newConcurrentAtomicARSWLockArray(Runnable.class); + this.execute = ArrayFactory.newArray(Runnable.class); + } + + /** + * Add a task to execute. + * + * @param task the task. + */ + @FromAnyThread + public void addToExecute(@NotNull Runnable task) { + waitTasks.runInWriteLock(task, (tasks, toAdd) -> tasks.add(task)); + } + + /** + * Execute waited tasks. + */ + @JmeThread + public void execute() { + + if (waitTasks.isEmpty()) { + return; + } + + waitTasks.runInWriteLock(execute, ArrayUtils::move); + try { + execute.forEach(JmeThreadExecutor::execute); + } finally { + execute.clear(); + } + } + + @JmeThread + private static void execute(@NotNull Runnable runnable) { + try { + runnable.run(); + } catch (Exception e) { + EditorUtils.handleException(LOGGER, getInstance(), e); + } + } +} diff --git a/src/main/java/com/ss/editor/file/converter/FileConverter.java b/src/main/java/com/ss/builder/file/converter/FileConverter.java similarity index 85% rename from src/main/java/com/ss/editor/file/converter/FileConverter.java rename to src/main/java/com/ss/builder/file/converter/FileConverter.java index 6977a803..f96e61db 100644 --- a/src/main/java/com/ss/editor/file/converter/FileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/FileConverter.java @@ -1,6 +1,7 @@ -package com.ss.editor.file.converter; +package com.ss.builder.file.converter; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/FileConverterDescription.java b/src/main/java/com/ss/builder/file/converter/FileConverterDescription.java similarity index 94% rename from src/main/java/com/ss/editor/file/converter/FileConverterDescription.java rename to src/main/java/com/ss/builder/file/converter/FileConverterDescription.java index c6f0d22f..e77d65e7 100644 --- a/src/main/java/com/ss/editor/file/converter/FileConverterDescription.java +++ b/src/main/java/com/ss/builder/file/converter/FileConverterDescription.java @@ -1,7 +1,8 @@ -package com.ss.editor.file.converter; +package com.ss.builder.file.converter; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/file/converter/FileConverterRegistry.java b/src/main/java/com/ss/builder/file/converter/FileConverterRegistry.java new file mode 100644 index 00000000..c4ccbd8c --- /dev/null +++ b/src/main/java/com/ss/builder/file/converter/FileConverterRegistry.java @@ -0,0 +1,81 @@ +package com.ss.builder.file.converter; + +import static com.ss.rlib.common.util.FileUtils.containsExtensions; +import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.file.converter.impl.*; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.file.converter.impl.*; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The registry of file converters. + * + * @author JavaSaBr + */ +public class FileConverterRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(FileConverterRegistry.class); + + /** + * @see FileConverterDescription + */ + public static final String EP_DESCRIPTORS = "FileConverterRegistry#descriptions"; + + private static final ExtensionPoint DESCRIPTIONS = + ExtensionPointManager.register(EP_DESCRIPTORS); + + private static final FileConverterRegistry INSTANCE = new FileConverterRegistry(); + + @FromAnyThread + public static @NotNull FileConverterRegistry getInstance() { + return INSTANCE; + } + + private FileConverterRegistry() { + + DESCRIPTIONS.register(BlendToJ3oFileConverter.DESCRIPTION) + .register(FbxToJ3oFileConverter.DESCRIPTION) + .register(ObjToJ3oFileConverter.DESCRIPTION) + .register(SceneToJ3oFileConverter.DESCRIPTION) + .register(MeshXmlToJ3oFileConverter.DESCRIPTION) + .register(XbufToJ3oFileConverter.DESCRIPTION) + .register(GltfToJ3oFileConverter.DESCRIPTION); + + LOGGER.info("initialized."); + } + + /** + * Get the list of available converters for the file. + * + * @param path the path. + * @return the list of available converters. + */ + @FromAnyThread + public @NotNull Array getDescriptions(@NotNull Path path) { + return DESCRIPTIONS.getExtensions().stream() + .filter(desc -> containsExtensions(desc.getExtensions(), path)) + .collect(toArray(FileConverterDescription.class)); + } + + /** + * Create a file converter using the converter description. + * + * @param description the converter description. + * @param file the file. + * @return the new converter. + */ + @FromAnyThread + public @NotNull FileConverter newCreator(@NotNull FileConverterDescription description, @NotNull Path file) { + return description.getConstructor() + .get(); + } +} diff --git a/src/main/java/com/ss/editor/file/converter/impl/AbstractFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/AbstractFileConverter.java similarity index 84% rename from src/main/java/com/ss/editor/file/converter/impl/AbstractFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/AbstractFileConverter.java index ba3c065d..0fbef60b 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/AbstractFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/AbstractFileConverter.java @@ -1,14 +1,21 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; import static com.ss.rlib.common.util.FileUtils.containsExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.file.converter.FileConverter; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.file.converter.FileConverter; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.util.FileUtils; @@ -94,7 +101,7 @@ public void convert(@NotNull final Path source, @NotNull final Path destination) } } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); EXECUTOR_MANAGER.addFxTask(() -> notifyFileCreatedImpl(null)); } }); diff --git a/src/main/java/com/ss/editor/file/converter/impl/AbstractModelFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/AbstractModelFileConverter.java similarity index 84% rename from src/main/java/com/ss/editor/file/converter/impl/AbstractModelFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/AbstractModelFileConverter.java index bc1b2e11..75d882df 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/AbstractModelFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/AbstractModelFileConverter.java @@ -1,9 +1,6 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION; import static com.ss.editor.extension.property.EditablePropertyType.*; -import static com.ss.editor.util.EditorUtil.*; import static com.ss.rlib.common.util.FileUtils.containsExtensions; import static com.ss.rlib.common.util.FileUtils.normalizeName; import static com.ss.rlib.common.util.ObjectUtils.notNull; @@ -15,17 +12,18 @@ import com.jme3.material.Material; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.TangentGenerator; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.util.MaterialSerializer; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.util.TangentGenerator; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.VarTable; @@ -74,7 +72,7 @@ public void convert(@NotNull final Path source, @NotNull final Path destination) } final String resultName = FileUtils.getNameWithoutExtension(source); - final Path assetDestination = getAssetFile(destination.getParent()); + final Path assetDestination = EditorUtils.getAssetFile(destination.getParent()); final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); definitions.add(new PropertyDefinition(STRING, Messages.MODEL_CONVERTER_DIALOG_RESULT_NAME, PROP_RESULT_NAME, resultName)); @@ -122,7 +120,7 @@ private void convert(@NotNull final Path source, @NotNull final VarTable vars) { try { convertImpl(source, vars); } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); } }); @@ -135,17 +133,17 @@ private void convert(@NotNull final Path source, @NotNull final VarTable vars) { private void convertImpl(@NotNull final Path source, @NotNull final VarTable vars) throws IOException { final String filename = vars.getString(PROP_RESULT_NAME); - final Path destinationFolder = notNull(getRealFile(vars.get(PROP_DESTINATION, Path.class))); + final Path destinationFolder = notNull(EditorUtils.getRealFile(vars.get(PROP_DESTINATION, Path.class))); final Path destination = destinationFolder.resolve(filename + "." + FileExtensions.JME_OBJECT); final boolean isOverwrite = Files.exists(destination); - final Path assetFile = notNull(getAssetFile(source), "Not found asset file for " + source); - final ModelKey modelKey = new ModelKey(toAssetPath(assetFile)); + final Path assetFile = notNull(EditorUtils.getAssetFile(source), "Not found asset file for " + source); + final ModelKey modelKey = new ModelKey(EditorUtils.toAssetPath(assetFile)); - final AssetManager assetManager = EditorUtil.getAssetManager(); + final AssetManager assetManager = EditorUtils.getAssetManager(); final Spatial model = assetManager.loadAsset(modelKey); - if (EDITOR_CONFIG.getBoolean(PREF_TANGENT_GENERATION, PREF_DEFAULT_TANGENT_GENERATION)) { + if (EDITOR_CONFIG.getBoolean(DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION, DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION)) { TangentGenerator.useMikktspaceGenerator(model); } @@ -187,7 +185,7 @@ private void storeMaterials(@NotNull final Path materialsFolder, final boolean c @NotNull final String materialName, @NotNull final Geometry geometry) { final Path resultFile = materialsFolder.resolve(normalizeName(materialName) + "." + FileExtensions.JME_MATERIAL); - final Path assetFile = getAssetFile(resultFile); + final Path assetFile = EditorUtils.getAssetFile(resultFile); if (assetFile == null) { LOGGER.warning("Can't get asset file for the file " + resultFile); @@ -200,13 +198,13 @@ private void storeMaterials(@NotNull final Path materialsFolder, final boolean c try (PrintWriter pout = new PrintWriter(Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE))) { pout.println(MaterialSerializer.serializeToString(currentMaterial)); } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); } } - final String assetPath = toAssetPath(assetFile); + final String assetPath = EditorUtils.toAssetPath(assetFile); - final AssetManager assetManager = EditorUtil.getAssetManager(); + final AssetManager assetManager = EditorUtils.getAssetManager(); geometry.setMaterial(assetManager.loadMaterial(assetPath)); } diff --git a/src/main/java/com/ss/editor/file/converter/impl/BlendToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/BlendToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/BlendToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/BlendToJ3oFileConverter.java index 657803be..745d7fa4 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/BlendToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/BlendToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/impl/FbxToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/FbxToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/FbxToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/FbxToJ3oFileConverter.java index 60dd52e4..aab4e32a 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/FbxToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/FbxToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/impl/GltfToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/GltfToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/GltfToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/GltfToJ3oFileConverter.java index c8a3b0ea..e49fbc54 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/GltfToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/GltfToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/impl/MeshXmlToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/MeshXmlToJ3oFileConverter.java similarity index 87% rename from src/main/java/com/ss/editor/file/converter/impl/MeshXmlToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/MeshXmlToJ3oFileConverter.java index 08589330..14bf6276 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/MeshXmlToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/MeshXmlToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/file/converter/impl/ObjToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/ObjToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/ObjToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/ObjToJ3oFileConverter.java index b1c4f57b..91da6be0 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/ObjToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/ObjToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/impl/SceneToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/SceneToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/SceneToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/SceneToJ3oFileConverter.java index de3c1cb4..0ddbc1ac 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/SceneToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/SceneToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/converter/impl/XbufToJ3oFileConverter.java b/src/main/java/com/ss/builder/file/converter/impl/XbufToJ3oFileConverter.java similarity index 82% rename from src/main/java/com/ss/editor/file/converter/impl/XbufToJ3oFileConverter.java rename to src/main/java/com/ss/builder/file/converter/impl/XbufToJ3oFileConverter.java index bba7187f..63bc9bb9 100644 --- a/src/main/java/com/ss/editor/file/converter/impl/XbufToJ3oFileConverter.java +++ b/src/main/java/com/ss/builder/file/converter/impl/XbufToJ3oFileConverter.java @@ -1,8 +1,10 @@ -package com.ss.editor.file.converter.impl; +package com.ss.builder.file.converter.impl; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandler.java b/src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandler.java similarity index 78% rename from src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandler.java rename to src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandler.java index b6518a0b..74658610 100644 --- a/src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandler.java +++ b/src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandler.java @@ -1,7 +1,7 @@ -package com.ss.editor.file.delete.handler; +package com.ss.builder.file.handler.delete; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; @@ -19,7 +19,7 @@ public interface FileDeleteHandler extends Cloneable { * @param file the file to delete. */ @FxThread - void preDelete(@NotNull final Path file); + void preDelete(@NotNull Path file); /** * Handle a file to delete after deleting. @@ -27,7 +27,7 @@ public interface FileDeleteHandler extends Cloneable { * @param file the deleted file. */ @FxThread - void postDelete(@NotNull final Path file); + void postDelete(@NotNull Path file); /** * Check that the file need to handle. diff --git a/src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandlerFactory.java b/src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandlerFactory.java new file mode 100644 index 00000000..23979569 --- /dev/null +++ b/src/main/java/com/ss/builder/file/handler/delete/FileDeleteHandlerFactory.java @@ -0,0 +1,38 @@ +package com.ss.builder.file.handler.delete; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.file.handler.delete.impl.DeleteMaterialsModelFileDeleteHandler; +import com.ss.rlib.common.util.array.ArrayCollectors; +import org.jetbrains.annotations.NotNull; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; + +import java.nio.file.Path; + +/** + * The factory of delete handlers of deleted file. + * + * @author JavaSaBr + */ +public class FileDeleteHandlerFactory { + + private static final Array HANDLERS = ArrayFactory.newArray(FileDeleteHandler.class); + + static { + HANDLERS.add(new DeleteMaterialsModelFileDeleteHandler()); + } + + /** + * Find handlers for the file. + * + * @param file the file. + * @return the list of handlers. + */ + @FromAnyThread + public static @NotNull Array findFor(@NotNull Path file) { + return HANDLERS.stream() + .filter(handler -> handler.isNeedHandle(file)) + .map(FileDeleteHandler::clone) + .collect(ArrayCollectors.toArray(FileDeleteHandler.class)); + } +} diff --git a/src/main/java/com/ss/builder/file/handler/delete/impl/AbstractFileDeleteHandler.java b/src/main/java/com/ss/builder/file/handler/delete/impl/AbstractFileDeleteHandler.java new file mode 100644 index 00000000..2144b003 --- /dev/null +++ b/src/main/java/com/ss/builder/file/handler/delete/impl/AbstractFileDeleteHandler.java @@ -0,0 +1,45 @@ +package com.ss.builder.file.handler.delete.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.file.handler.delete.FileDeleteHandler; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The base implementation of {@link FileDeleteHandler}. + * + * @author JavaSaBr + */ +public abstract class AbstractFileDeleteHandler implements FileDeleteHandler { + + protected static final Logger LOGGER = LoggerManager.getLogger(FileDeleteHandler.class); + + @Override + @FxThread + public void preDelete(@NotNull Path file) { + } + + @Override + @FxThread + public void postDelete(@NotNull Path file) { + + } + + @Override + @FxThread + public boolean isNeedHandle(@NotNull Path file) { + return false; + } + + @Override + public @NotNull FileDeleteHandler clone() { + try { + return (FileDeleteHandler) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java b/src/main/java/com/ss/builder/file/handler/delete/impl/DeleteMaterialsModelFileDeleteHandler.java similarity index 79% rename from src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java rename to src/main/java/com/ss/builder/file/handler/delete/impl/DeleteMaterialsModelFileDeleteHandler.java index a85515eb..90ed08a9 100644 --- a/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java +++ b/src/main/java/com/ss/builder/file/handler/delete/impl/DeleteMaterialsModelFileDeleteHandler.java @@ -1,16 +1,14 @@ -package com.ss.editor.file.delete.handler.impl; +package com.ss.builder.file.handler.delete.impl; -import static com.ss.editor.FileExtensions.JME_OBJECT; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.ui.dialog.ConfirmDialog; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; @@ -42,9 +40,9 @@ public DeleteMaterialsModelFileDeleteHandler() { public void preDelete(@NotNull final Path file) { super.preDelete(file); - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Path assetFile = notNull(getAssetFile(file)); - final String assetPath = toAssetPath(assetFile); + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Path assetFile = notNull(EditorUtils.getAssetFile(file)); + final String assetPath = EditorUtils.toAssetPath(assetFile); final Spatial model; @@ -97,7 +95,7 @@ private void handle(@Nullable final Boolean result) { return; } - getAssetKeys().stream().map(EditorUtil::getRealFile) + getAssetKeys().stream().map(EditorUtils::getRealFile) .filter(Files::exists) .forEach(FileUtils::delete); } @@ -105,6 +103,6 @@ private void handle(@Nullable final Boolean result) { @Override public boolean isNeedHandle(@NotNull final Path file) { final String extension = FileUtils.getExtension(file); - return JME_OBJECT.equals(extension); + return FileExtensions.JME_OBJECT.equals(extension); } } diff --git a/src/main/java/com/ss/editor/file/reader/DdsReader.java b/src/main/java/com/ss/builder/file/reader/DdsReader.java similarity index 99% rename from src/main/java/com/ss/editor/file/reader/DdsReader.java rename to src/main/java/com/ss/builder/file/reader/DdsReader.java index 40009204..dfb201ce 100644 --- a/src/main/java/com/ss/editor/file/reader/DdsReader.java +++ b/src/main/java/com/ss/builder/file/reader/DdsReader.java @@ -12,7 +12,7 @@ * http://3dtech.jp/wiki/index.php?DDSReader */ -package com.ss.editor.file.reader; +package com.ss.builder.file.reader; /** * The implementation of DDS reader. diff --git a/src/main/java/com/ss/editor/file/reader/TgaReader.java b/src/main/java/com/ss/builder/file/reader/TgaReader.java similarity index 98% rename from src/main/java/com/ss/editor/file/reader/TgaReader.java rename to src/main/java/com/ss/builder/file/reader/TgaReader.java index 99aa16c9..a488094a 100644 --- a/src/main/java/com/ss/editor/file/reader/TgaReader.java +++ b/src/main/java/com/ss/builder/file/reader/TgaReader.java @@ -1,4 +1,4 @@ -package com.ss.editor.file.reader; +package com.ss.builder.file.reader; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/FxConstants.java b/src/main/java/com/ss/builder/fx/FxConstants.java similarity index 90% rename from src/main/java/com/ss/editor/ui/FxConstants.java rename to src/main/java/com/ss/builder/fx/FxConstants.java index 6dfe52f7..27cfe267 100644 --- a/src/main/java/com/ss/editor/ui/FxConstants.java +++ b/src/main/java/com/ss/builder/fx/FxConstants.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui; +package com.ss.builder.fx; /** * The interface with FX constants. diff --git a/src/main/java/com/ss/editor/ui/Icons.java b/src/main/java/com/ss/builder/fx/Icons.java similarity index 99% rename from src/main/java/com/ss/editor/ui/Icons.java rename to src/main/java/com/ss/builder/fx/Icons.java index 037b6eb8..65c31f1a 100644 --- a/src/main/java/com/ss/editor/ui/Icons.java +++ b/src/main/java/com/ss/builder/fx/Icons.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui; +package com.ss.builder.fx; -import com.ss.editor.manager.FileIconManager; +import com.ss.builder.manager.FileIconManager; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/action/MenuModifyingAction.java b/src/main/java/com/ss/builder/fx/action/MenuModifyingAction.java new file mode 100644 index 00000000..1f48b675 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/action/MenuModifyingAction.java @@ -0,0 +1,52 @@ +package com.ss.builder.fx.action; + +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.action.ModifyingAction; +import com.ss.editor.extension.scene.app.state.EditableSceneAppState; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.ModifyingActionOperation; +import javafx.scene.control.MenuItem; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link ModifyingAction} from {@link EditableSceneAppState}. + * + * @author JavaSaBr + */ +public class MenuModifyingAction extends MenuItem { + + /** + * The action. + */ + @NotNull + private final ModifyingAction action; + + /** + * The change consumer. + */ + @NotNull + private final ChangeConsumer changeConsumer; + + /** + * The action's owner. + */ + @NotNull + private final Object owner; + + public MenuModifyingAction( + @NotNull ModifyingAction action, + @NotNull ChangeConsumer changeConsumer, + @NotNull Object owner + ) { + this.action = action; + this.changeConsumer = changeConsumer; + this.owner = owner; + setText(action.getName()); + setOnAction(event -> execute()); + } + + @FxThread + private void execute() { + changeConsumer.execute(new ModifyingActionOperation(action, owner)); + } +} diff --git a/src/main/java/com/ss/builder/fx/builder/EditorFxSceneBuilder.java b/src/main/java/com/ss/builder/fx/builder/EditorFxSceneBuilder.java new file mode 100644 index 00000000..10277bf9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/builder/EditorFxSceneBuilder.java @@ -0,0 +1,157 @@ +package com.ss.builder.fx.builder; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.AsyncEventManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.AssetComponent; +import com.ss.builder.fx.component.bar.EditorMenuBarComponent; +import com.ss.builder.fx.component.EditorAreaComponent; +import com.ss.builder.fx.component.log.LogView; +import com.ss.builder.fx.component.split.pane.GlobalBottomToolSplitPane; +import com.ss.builder.fx.component.split.pane.GlobalLeftToolSplitPane; +import com.ss.builder.fx.component.tab.GlobalBottomToolComponent; +import com.ss.builder.fx.component.tab.GlobalLeftToolComponent; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.event.EventRedirector; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.fx.scene.EditorFxScene; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.Group; +import javafx.scene.control.Menu; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import org.jetbrains.annotations.NotNull; + +/** + * The scene builder for building a scene for the Editor. + * + * @author JavaSaBr + */ +public class EditorFxSceneBuilder { + + private static final Logger LOGGER = LoggerManager.getLogger(EditorFxSceneBuilder.class); + + /** + * Build the Editor's main scene. + * + * @param window the main window. + * @return the main scene. + */ + @FxThread + public static @NotNull EditorFxScene build(@NotNull Stage window) { + + // init FX classes + var t1 = Menu.ON_SHOWN; + + var editorConfig = EditorConfig.getInstance(); + var theme = editorConfig.getEnum(DefaultSettingsProvider.Preferences.PREF_UI_THEME, DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME); + + var root = new Group(); + var scene = new EditorFxScene(root); + scene.setFill(theme.getBackgroundColor()); + scene.setRoot(root); + scene.incrementLoading(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(() -> build(scene, window)) + .add(FxSceneCreatedEvent.EVENT_TYPE) + .add(ImageSystemInitializedEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(() -> attachScene(window, scene)) + .add(CssAppliedEvent.EVENT_TYPE) + .buildAndRegister(); + + LOGGER.info("created an empty scene."); + + return scene; + } + + /** + * Attach the created scene to the window. + * + * @param window the window. + * @param scene the scene. + */ + @BackgroundThread + private static void attachScene(@NotNull Stage window, @NotNull EditorFxScene scene) { + ExecutorManager.getInstance() + .addFxTask(() -> attachSceneInFx(window, scene)); + } + + @FxThread + private static void attachSceneInFx(@NotNull Stage window, @NotNull EditorFxScene scene) { + + window.setScene(scene); + + LOGGER.info("the main scene is attached."); + + AsyncEventManager.getInstance() + .notify(new FxSceneAttachedEvent()); + } + + /** + * Build main scene components in background. + * + * @param scene the main scene. + * @param window the main window. + */ + @BackgroundThread + private static void build(@NotNull EditorFxScene scene, @NotNull Stage window) { + + var container = scene.getContainer(); + var canvas = scene.getCanvas(); + var barComponent = new EditorMenuBarComponent(); + var editorAreaComponent = new EditorAreaComponent(); + + new EventRedirector(editorAreaComponent, canvas, window); + + var leftSplitContainer = new GlobalLeftToolSplitPane(scene); + leftSplitContainer.prefHeightProperty() + .bind(container.heightProperty()); + + var bottomSplitContainer = new GlobalBottomToolSplitPane(scene); + var globalLeftToolComponent = new GlobalLeftToolComponent(leftSplitContainer); + globalLeftToolComponent.addComponent(new AssetComponent(), Messages.EDITOR_TOOL_ASSET); + + var globalBottomToolComponent = new GlobalBottomToolComponent(bottomSplitContainer); + globalBottomToolComponent.addComponent(LogView.getInstance(), Messages.LOG_VIEW_TITLE); + + leftSplitContainer.initFor(globalLeftToolComponent, bottomSplitContainer); + bottomSplitContainer.initFor(globalBottomToolComponent, editorAreaComponent); + + FxUtils.addClass(leftSplitContainer, bottomSplitContainer, + CssClasses.MAIN_SPLIT_PANEL); + + leftSplitContainer.prefWidthProperty() + .bind(container.widthProperty()); + barComponent.prefWidthProperty() + .bind(container.widthProperty()); + + LOGGER.info("created the main components."); + + ExecutorManager.getInstance() + .addFxTask(() -> finishBuildingScene(container, barComponent, leftSplitContainer)); + } + + @FxThread + private static void finishBuildingScene( + @NotNull StackPane container, + @NotNull EditorMenuBarComponent barComponent, + @NotNull GlobalLeftToolSplitPane leftSplitContainer + ) { + + FxUtils.addChild(container, new VBox(barComponent, leftSplitContainer)); + + LOGGER.info("put main components to the main scene."); + + AsyncEventManager.getInstance() + .notify(new FxContextCreatedEvent()); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/EditorAreaComponent.java b/src/main/java/com/ss/builder/fx/component/EditorAreaComponent.java new file mode 100644 index 00000000..9d2db746 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/EditorAreaComponent.java @@ -0,0 +1,598 @@ +package com.ss.builder.fx.component; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.JfxApplication; +import com.ss.builder.JmeApplication; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.editor.event.HideFileEditorEvent; +import com.ss.builder.editor.event.ShowedFileEditorEvent; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.fx.scene.EditorFxScene; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.file.converter.FileConverterRegistry; +import com.ss.builder.fx.component.creator.FileCreatorRegistry; +import com.ss.builder.editor.EditorRegistry; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.event.ClosedFileEditorEvent; +import com.ss.builder.editor.event.FileRenamedFileEditorEvent; +import com.ss.rlib.common.concurrent.util.ThreadUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.array.ConcurrentArray; +import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.ObservableUtils; +import javafx.collections.ListChangeListener; +import javafx.event.Event; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The component for containing editors. + * + * @author JavaSaBr + */ +public class EditorAreaComponent extends TabPane implements ScreenComponent { + + private static final Logger LOGGER = LoggerManager.getLogger(EditorAreaComponent.class); + + private static final String COMPONENT_ID = "EditorAreaComponent"; + private static final String KEY_EDITOR = "jMB.node.editor"; + + /** + * Require a file editor's reference from the tab. + * + * @param tab the tab. + * @return the file editor. + */ + @FxThread + private static @NotNull FileEditor requireFileEditor(@NotNull Tab tab) { + return (FileEditor) notNull(tab.getProperties() + .get(KEY_EDITOR)); + } + + /** + * The table of opened editors. + */ + @NotNull + private final ConcurrentObjectDictionary openedEditors; + + /** + * The list of opened files. + */ + @NotNull + private final ConcurrentArray openingFiles; + + /** + * True if need to ignore change events. + */ + private boolean ignoreOpenedFiles; + + public EditorAreaComponent() { + setPickOnBounds(true); + setId(CssIds.EDITOR_AREA_COMPONENT); + + this.openedEditors = DictionaryFactory.newConcurrentAtomicObjectDictionary(); + this.openingFiles = ArrayFactory.newConcurrentStampedLockArray(Path.class); + + getTabs().addListener(this::processChangeTabs); + + FxControlUtils.onSelectedTabChange(this, this::switchEditor); + + FxEventManager.getInstance() + .addEventHandler(RequestedOpenFileEvent.EVENT_TYPE, this::processOpenFile) + .addEventHandler(RequestedCreateFileEvent.EVENT_TYPE, this::processCreateFile) + .addEventHandler(RequestedConvertFileEvent.EVENT_TYPE, this::processConvertFile) + .addEventHandler(RenamedFileEvent.EVENT_TYPE, this::processEvent) + .addEventHandler(MovedFileEvent.EVENT_TYPE, this::processEvent) + .addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, this::processEvent); + } + + @FxThread + private void switchEditor(@Nullable Tab oldValue, @Nullable Tab newValue) { + + BorderPane current3dArea = null; + BorderPane new3dArea = null; + + Path newCurrentFile = null; + + if (newValue != null) { + + var fileEditor = requireFileEditor(newValue); + fileEditor.notify(ShowedFileEditorEvent.getInstance()); + + newCurrentFile = fileEditor.getFile(); + new3dArea = fileEditor.get3dArea(); + } + + if (oldValue != null) { + + var fileEditor = requireFileEditor(oldValue); + fileEditor.notify(HideFileEditorEvent.getInstance()); + + current3dArea = fileEditor.get3dArea(); + } + + var scene = (EditorFxScene) getScene(); + var canvas = scene.getCanvas(); + + if (new3dArea != null) { + new3dArea.setCenter(canvas); + } else if (current3dArea != null) { + current3dArea.setCenter(null); + scene.hideCanvas(); + } + + WorkspaceManager.getInstance() + .requiredCurrentWorkspace() + .updateCurrentEditedFile(newCurrentFile); + + ExecutorManager.getInstance() + .addJmeTask(() -> processShowEditor(oldValue, newValue)); + } + + /** + * Handle the event of changing a current asset folder. + */ + @FxThread + private void processEvent(@NotNull ChangedCurrentAssetFolderEvent event) { + setIgnoreOpenedFiles(true); + try { + getTabs().clear(); + loadOpenedFiles(); + } finally { + setIgnoreOpenedFiles(false); + } + } + + /** + * Set true if need to ignore change events. + * + * @param ignoreOpenedFiles true if need to ignore change events. + */ + @FromAnyThread + private void setIgnoreOpenedFiles(boolean ignoreOpenedFiles) { + this.ignoreOpenedFiles = ignoreOpenedFiles; + } + + /** + * Return true if need to ignore change events. + * + * @return true if need to ignore change events. + */ + @FromAnyThread + private boolean isIgnoreOpenedFiles() { + return ignoreOpenedFiles; + } + + /** + * Handle the event of renamed file. + */ + @FxThread + private void processEvent(@NotNull RenamedFileEvent event) { + handleMovedFiles(event.getPrevFile(), event.getNewFile()); + } + + /** + * Handle the event of moved file. + */ + @FxThread + private void processEvent(@NotNull MovedFileEvent event) { + handleMovedFiles(event.getPrevFile(), event.getNewFile()); + } + + /** + * Handle a moved/renamed file. + * + * @param prevFile the prev version of the file. + * @param newFile the new version of the file. + */ + @FxThread + private void handleMovedFiles(@NotNull Path prevFile, @NotNull Path newFile) { + + var stamp = openedEditors.writeLock(); + try { + + var files = openedEditors.keyArray(Path.class); + + for (var file : files) { + + if (!file.startsWith(prevFile)) { + continue; + } + + var tab = openedEditors.get(file); + + if (tab == null) { + LOGGER.warning("Not found a tab for the opened file " + file); + continue; + } + + var fileEditor = requireFileEditor(tab); + fileEditor.notify(new FileRenamedFileEditorEvent(this, prevFile, newFile)); + + if (fileEditor.isDirty()) { + tab.setText("*" + fileEditor.getFileName()); + } else { + tab.setText(fileEditor.getFileName()); + } + + var editFile = fileEditor.getFile(); + + openedEditors.remove(file); + openedEditors.put(editFile, tab); + + WorkspaceManager.getInstance() + .getCurrentWorkspaceOpt() + .stream() + .peek(workspace -> workspace.removeOpenedFile(file)) + .forEach(workspace -> workspace.addOpenedFile(editFile, fileEditor)); + } + + } finally { + openedEditors.writeUnlock(stamp); + } + } + + /** + * Handle the request to convert a file. + */ + @FxThread + private void processConvertFile(@NotNull RequestedConvertFileEvent event) { + + FileConverterRegistry.getInstance() + .newCreator(event.getDescription(), event.getFile()) + .convert(event.getFile()); + } + + /** + * Handle the request to create a file. + */ + @FxThread + private void processCreateFile(@NotNull RequestedCreateFileEvent event) { + + FileCreatorRegistry.getInstance() + .newCreatorOpt(event.getDescriptor(), event.getFile()) + .ifPresent(fileCreator -> fileCreator.start(event.getFile())); + } + + /** + * Handle the request to close a file editor. + */ + @FxThread + private void processChangeTabs(@NotNull ListChangeListener.Change change) { + + if (!change.next()) { + return; + } + + var removed = change.getRemoved(); + + if (removed == null || removed.isEmpty()) { + return; + } + + removed.forEach(tab -> { + + var fileEditor = requireFileEditor(tab); + var editFile = fileEditor.getFile(); + + openedEditors.runInWriteLock(editFile, ObjectDictionary::remove); + + fileEditor.notify(ClosedFileEditorEvent.getInstance()); + + if (isIgnoreOpenedFiles()) { + return; + } + + WorkspaceManager.getInstance() + .getCurrentWorkspaceOpt() + .ifPresent(workspace -> workspace.removeOpenedFile(editFile)); + }); + } + + /** + * Get the current showed editor. + * + * @return the current editor. + */ + @FxThread + public @Nullable FileEditor getCurrentEditor() { + + var selectedTab = getSelectionModel() + .getSelectedItem(); + + if (selectedTab == null) { + return null; + } + + return (FileEditor) selectedTab.getProperties() + .get(KEY_EDITOR); + } + + /** + * Handle a changed active file editor. + * + * @param prevTab the previous editor. + * @param newTab the new editor. + */ + @JmeThread + private void processShowEditor(@Nullable Tab prevTab, @Nullable Tab newTab) { + + var stateManager = EditorUtils.getStateManager(); + var canvas = EditorUtils.getFxScene() + .getCanvas(); + + var sceneProcessor = JfxApplication.getInstance() + .getSceneProcessor(); + + boolean enabled = false; + + if (prevTab != null) { + var parts = requireFileEditor(prevTab).get3dParts(); + parts.forEach(stateManager::detach); + } + + if (newTab != null) { + + var parts = requireFileEditor(newTab).get3dParts(); + parts.forEach(stateManager::attach); + + enabled = parts.size() > 0; + } + + if (sceneProcessor.isEnabled() != enabled) { + var result = enabled; + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + ThreadUtils.sleep(100); + canvas.setOpacity(result ? 1D : 0D); + sceneProcessor.setEnabled(result); + }); + } + } + + /** + * Handle the request to open a file. + */ + @FxThread + private void processOpenFile(@NotNull RequestedOpenFileEvent event) { + + var file = event.getFile(); + var tab = openedEditors.getInReadLock(file, ObjectDictionary::get); + + if (tab != null) { + getSelectionModel().select(tab); + return; + } + + var stamp = openingFiles.writeLock(); + try { + + if (openingFiles.contains(file)) { + return; + } + + openingFiles.add(file); + + UiUtils.incrementLoading(); + + ExecutorManager.getInstance() + .addBackgroundTask(() -> processOpenFileInBackground(event, file)); + + } finally { + openingFiles.writeUnlock(stamp); + } + } + + @BackgroundThread + private void processOpenFileInBackground(@NotNull RequestedOpenFileEvent event, @NotNull Path file) { + + FileEditor editor; + try { + + var description = event.getDescription(); + var editorRegistry = EditorRegistry.getInstance(); + + editor = description == null ? editorRegistry.createEditorFor(file) : + editorRegistry.createEditorFor(description, file); + + } catch (Throwable e) { + EditorUtils.handleException(null, this, new Exception(e)); + UiUtils.decrementLoading(); + openingFiles.runInWriteLock(file, Array::fastRemove); + return; + } + + if (editor == null) { + UiUtils.decrementLoading(); + openingFiles.runInWriteLock(file, Array::fastRemove); + return; + } + + var resultEditor = editor; + + var jmeApplication = JmeApplication.getInstance(); + var stamp = jmeApplication.asyncLock(); + try { + editor.openFile(file); + } catch (Throwable e) { + EditorUtils.handleException(null, this, new Exception(e)); + + openingFiles.runInWriteLock(file, Array::fastRemove); + + WorkspaceManager.getInstance() + .requiredCurrentWorkspace() + .removeOpenedFile(file); + + UiUtils.decrementLoading(); + + ExecutorManager.getInstance() + .addFxTask(() -> resultEditor.notify(ClosedFileEditorEvent.getInstance())); + + return; + + } finally { + jmeApplication.asyncUnlock(stamp); + } + + ExecutorManager.getInstance() + .addFxTask(() -> addEditor(resultEditor, event.isNeedShow())); + } + + /** + * Add and open the new file editor. + * + * @param editor the editor + * @param needShow the need show + */ + @FxThread + private void addEditor(@NotNull FileEditor editor, boolean needShow) { + + var editFile = editor.getFile(); + var iconManager = FileIconManager.getInstance(); + + var tab = new Tab(editor.getFileName()); + tab.setGraphic(new ImageView(iconManager.getIcon(editFile, FileIconManager.DEFAULT_FILE_ICON_SIZE))); + tab.setContent(editor.getUiPage()); + tab.setOnCloseRequest(event -> handleRequestToCloseEditor(editor, tab, event)); + tab.getProperties().put(KEY_EDITOR, editor); + + ObservableUtils.onChanges(editor.dirtyProperty()) + .onChangeIf(dirty -> dirty, () -> tab.setText("*" + editor.getFileName())) + .onChangeIf(dirty -> !dirty, () -> tab.setText(editor.getFileName())); + + getTabs().add(tab); + + if (needShow) { + getSelectionModel().select(tab); + } + + openedEditors.runInWriteLock(editFile, tab, ObjectDictionary::put); + openingFiles.runInWriteLock(editFile, Array::fastRemove); + + UiUtils.decrementLoading(); + + if (isIgnoreOpenedFiles()) { + return; + } + + WorkspaceManager.getInstance() + .getCurrentWorkspaceOpt() + .ifPresent(workspace -> workspace.addOpenedFile(editFile, editor)); + } + + @FxThread + private void handleRequestToCloseEditor(@NotNull FileEditor editor, @NotNull Tab tab, @NotNull Event event) { + + if (!editor.isDirty()) { + return; + } + + var question = Messages.EDITOR_AREA_SAVE_FILE_QUESTION + .replace("%file_name%", editor.getFileName()); + + var dialog = new ConfirmDialog(result -> { + + if (result == null) { + return; + } + + if (result) { + //FIXME editor.save(fileEditor -> getTabs().remove(tab)); + } else { + getTabs().remove(tab); + } + + }, question); + + dialog.show(); + event.consume(); + } + + @Override + @FromAnyThread + public @Nullable String getComponentId() { + return COMPONENT_ID; + } + + @Override + @BackgroundThread + public void notifyFinishBuild() { + ExecutorManager.getInstance() + .addFxTask(this::notifyFinishBuildInFx); + } + + @FxThread + private void notifyFinishBuildInFx() { + setIgnoreOpenedFiles(true); + try { + loadOpenedFiles(); + } finally { + setIgnoreOpenedFiles(false); + } + } + + /** + * Load all opened files. + */ + @FxThread + private void loadOpenedFiles() { + + var workspace = WorkspaceManager.getInstance() + .getCurrentWorkspace(); + + if (workspace == null) { + return; + } + + var assetFolder = workspace.getAssetFolder(); + var editFile = workspace.getCurrentEditedFile(); + + var openedFiles = workspace.getOpenedFiles(); + openedFiles.forEach((assetPath, editorId) -> { + + var description = EditorRegistry.getInstance() + .getDescription(editorId); + + if (description == null) { + return; + } + + var file = assetFolder.resolve(assetPath); + + if (!Files.exists(file)) { + return; + } + + var event = new RequestedOpenFileEvent(file); + event.setDescription(description); + event.setNeedShow(StringUtils.equals(assetPath, editFile)); + + processOpenFile(event); + }); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/ScreenComponent.java b/src/main/java/com/ss/builder/fx/component/ScreenComponent.java new file mode 100644 index 00000000..3c6dcdb8 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/ScreenComponent.java @@ -0,0 +1,32 @@ +package com.ss.builder.fx.component; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.Nullable; + +/** + * The interface to implement a scene component. + * + * @author JavaSaBr + */ +public interface ScreenComponent { + + /** + * Gets the component id. + * + * @return the component id. + */ + @FromAnyThread + default @Nullable String getComponentId() { + return null; + } + + /** + * Notify about finishing building the result scene. + */ + @BackgroundThread + default void notifyFinishBuild() { + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/AssetBarComponent.java b/src/main/java/com/ss/builder/fx/component/asset/AssetBarComponent.java new file mode 100644 index 00000000..4ec39f60 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/AssetBarComponent.java @@ -0,0 +1,31 @@ +package com.ss.builder.fx.component.asset; + +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedRefreshAssetEvent; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedRefreshAssetEvent; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +/** + * The toolbar of the {@link AssetComponent} with actions. + * + * @author JavaSaBr. + */ +public class AssetBarComponent extends HBox { + + private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); + + public AssetBarComponent() { + + var refreshAction = new Button(); + refreshAction.setGraphic(new ImageView(Icons.REFRESH_18)); + refreshAction.setOnAction(event -> FX_EVENT_MANAGER.notify(new RequestedRefreshAssetEvent())); + + FxUtils.addChild(this, refreshAction); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/asset/AssetComponent.java b/src/main/java/com/ss/builder/fx/component/asset/AssetComponent.java similarity index 81% rename from src/main/java/com/ss/editor/ui/component/asset/AssetComponent.java rename to src/main/java/com/ss/builder/fx/component/asset/AssetComponent.java index c699a4e4..fec53b08 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/AssetComponent.java +++ b/src/main/java/com/ss/builder/fx/component/asset/AssetComponent.java @@ -1,21 +1,37 @@ -package com.ss.editor.ui.component.asset; +package com.ss.builder.fx.component.asset; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.WorkspaceManager; -import com.ss.editor.ui.component.ScreenComponent; -import com.ss.editor.ui.component.asset.tree.ResourceTree; -import com.ss.editor.ui.component.asset.tree.resource.FolderResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElementFactory; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.css.CssIds; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.*; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.fx.component.ScreenComponent; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import com.ss.rlib.fx.util.FxUtils; @@ -291,7 +307,7 @@ public String getComponentId() { } @Override - @FxThread + @BackgroundThread public void notifyFinishBuild() { loadAssetFolder(); } @@ -305,6 +321,7 @@ private void loadAssetFolder() { return; } - getResourceTree().fill(currentAsset); + ExecutorManager.getInstance() + .addFxTask(() -> getResourceTree().fill(currentAsset)); } } diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/AssetTreeContextMenuFillerRegistry.java b/src/main/java/com/ss/builder/fx/component/asset/tree/AssetTreeContextMenuFillerRegistry.java new file mode 100644 index 00000000..b3646df4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/AssetTreeContextMenuFillerRegistry.java @@ -0,0 +1,83 @@ +package com.ss.builder.fx.component.asset.tree; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.impl.FileAssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.impl.ResourceAssetTreeSingleContextMenuFiller; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.impl.FileAssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.impl.ResourceAssetTreeSingleContextMenuFiller; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * The registry class to collect all available context menu filler. + * + * @author JavaSaBr + */ +public class AssetTreeContextMenuFillerRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(AssetTreeContextMenuFillerRegistry.class); + + /** + * @see AssetTreeSingleContextMenuFiller + */ + public static final String EP_SINGLE_FILLERS = "AssetTreeContextMenuFillerRegistry#singleFillers"; + + /** + * @see AssetTreeMultiContextMenuFiller + */ + public static final String EP_MULTI_FILLERS = "AssetTreeContextMenuFillerRegistry#multiFillers"; + + private static final ExtensionPoint SINGLE_FILLERS = + ExtensionPointManager.register(EP_SINGLE_FILLERS); + + private static final ExtensionPoint MULTI_FILLERS = + ExtensionPointManager.register(EP_MULTI_FILLERS); + + private static final AssetTreeContextMenuFillerRegistry INSTANCE = + new AssetTreeContextMenuFillerRegistry(); + + public static @NotNull AssetTreeContextMenuFillerRegistry getInstance() { + return INSTANCE; + } + + private AssetTreeContextMenuFillerRegistry() { + + SINGLE_FILLERS.register(new FileAssetTreeSingleContextMenuFiller()) + .register(new ResourceAssetTreeSingleContextMenuFiller()); + + MULTI_FILLERS.register(new FileAssetTreeSingleContextMenuFiller()) + .register(new ResourceAssetTreeSingleContextMenuFiller()); + + LOGGER.info("initialized."); + } + + /** + * Gets the list of available single context menu singleFillers. + * + * @return the list of single context menu filler. + */ + @FromAnyThread + public @NotNull List getSingleFillers() { + return SINGLE_FILLERS.getExtensions(); + } + + /** + * Gets the list of available multiply context menu singleFillers. + * + * @return the list of multiply context menu filler. + */ + @FromAnyThread + public @NotNull List getMultiFillers() { + return MULTI_FILLERS.getExtensions(); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java b/src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTree.java similarity index 88% rename from src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java rename to src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTree.java index fcdcd6eb..fc3b046e 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTree.java @@ -1,19 +1,27 @@ -package com.ss.editor.ui.component.asset.tree; +package com.ss.builder.fx.component.asset.tree; -import static com.ss.editor.ui.component.asset.tree.resource.ResourceElementFactory.createFor; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; -import static com.ss.editor.ui.util.UiUtils.hasFileInClipboard; +import static com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory.createFor; +import static com.ss.builder.fx.util.UiUtils.findItemForValue; +import static com.ss.builder.fx.util.UiUtils.hasFileInClipboard; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.component.asset.tree.context.menu.action.*; -import com.ss.editor.ui.component.asset.tree.resource.*; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.asset.tree.context.menu.action.*; +import com.ss.builder.fx.component.asset.tree.resource.*; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.asset.tree.context.menu.action.*; +import com.ss.builder.fx.component.asset.tree.resource.*; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.function.IntObjectConsumer; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; @@ -260,20 +268,6 @@ private void processChangedExpands(@NotNull TreeModificationEvent event) { getExpandHandler().ifPresent(handler -> handler.accept(getExpandedItemCount(), this)); - - repaint(); - } - - private void repaint() { - - //FIXME temp fix how to refresh - var stage = EditorUtil.getFxStage(); - var old = stage.getWidth(); - //stage.setWidth(old + 3); - //setLayoutX(20F); - - //Platform.runLater(() -> stage.setWidth(old)); - //Platform.runLater(() -> setLayoutX(0)); } /** @@ -408,8 +402,9 @@ public void setExtensionFilter(@NotNull Array extensionFilter) { * @param onLoadHandler the on load handler. */ @FromAnyThread - public void setOnLoadHandler(@Nullable Consumer onLoadHandler) { + public @NotNull ResourceTree setOnLoadHandler(@Nullable Consumer onLoadHandler) { this.onLoadHandler = onLoadHandler; + return this; } /** @@ -469,20 +464,11 @@ private boolean isReadOnly() { } if (selectedItems.size() >= 1) { - - updateSelectedElements(); - - var selectedElements = getSelectedElements(); - var stamp = selectedElements.readLock(); - try { - + updateSelectedElements().runInReadLock(resourceElements -> { for (var filler : CONTEXT_MENU_FILLER_REGISTRY.getMultiFillers()) { - filler.fill(selectedElements, items, actionTester); + filler.fill(resourceElements, items, actionTester); } - - } finally { - selectedElements.readUnlock(stamp); - } + }); } if (items.isEmpty()) { @@ -498,9 +484,10 @@ private boolean isReadOnly() { * @param rootFolder the root folder. */ @FxThread - public void fill(@NotNull Path rootFolder) { + public @NotNull ResourceTree fill(@NotNull Path rootFolder) { prepareToFill(); EXECUTOR_MANAGER.addBackgroundTask(() -> startBackgroundFill(rootFolder)); + return this; } /** @@ -606,7 +593,7 @@ private void updateExpandedElements() { * Update the list of selected elements. */ @FxThread - private void updateSelectedElements() { + private @NotNull ConcurrentArray updateSelectedElements() { var elements = getSelectedElements(); var stamp = elements.writeLock(); @@ -621,6 +608,8 @@ private void updateSelectedElements() { } finally { elements.writeUnlock(stamp); } + + return elements; } /** @@ -637,7 +626,7 @@ private void showLoading() { @BackgroundThread private void startBackgroundFill(@NotNull Path path) { - var rootElement = createFor(path); + var rootElement = ResourceElementFactory.createFor(path); var newRoot = new TreeItem(rootElement); newRoot.setExpanded(true); @@ -663,8 +652,6 @@ private void applyNewRoot(@NotNull TreeItem newRoot) { if (onLoadHandler != null) { onLoadHandler.accept(Boolean.TRUE); } - - repaint(); } /** @@ -692,7 +679,7 @@ private void startBackgroundFill(@NotNull Array paths) { @BackgroundThread private void startBackgroundRefresh(@NotNull Path assetFolder) { - var rootElement = createFor(assetFolder); + var rootElement = ResourceElementFactory.createFor(assetFolder); var newRoot = new TreeItem(rootElement); newRoot.setExpanded(true); @@ -705,7 +692,7 @@ private void startBackgroundRefresh(@NotNull Path assetFolder) { expandedElements.sort(COMPARATOR); expandedElements.forEach(element -> { - var item = findItemForValue(newRoot, element); + var item = UiUtils.findItemForValue(newRoot, element); if (item == null) { return; } @@ -745,7 +732,7 @@ private void restoreSelection() { var selectionModel = getSelectionModel(); selectedElements.stream() - .map(resourceElement -> findItemForValue(getRoot(), resourceElement)) + .map(resourceElement -> UiUtils.findItemForValue(getRoot(), resourceElement)) .filter(Objects::nonNull) .forEach(selectionModel::select); @@ -804,26 +791,26 @@ public void notifyCreated(@NotNull Path file) { return; } - var fileElement = createFor(file); + var fileElement = ResourceElementFactory.createFor(file); - var fileItem = findItemForValue(getRoot(), fileElement); + var fileItem = UiUtils.findItemForValue(getRoot(), fileElement); if (fileItem != null) { return; } - var element = createFor(folder); - var folderItem = findItemForValue(getRoot(), element); + var element = ResourceElementFactory.createFor(folder); + var folderItem = UiUtils.findItemForValue(getRoot(), element); if (folderItem == null) { notifyCreated(folder); - folderItem = findItemForValue(getRoot(), folder); + folderItem = UiUtils.findItemForValue(getRoot(), folder); } if (folderItem == null) { return; } - var newItem = new TreeItem(createFor(file)); + var newItem = new TreeItem(ResourceElementFactory.createFor(file)); fill(newItem); @@ -841,8 +828,8 @@ public void notifyCreated(@NotNull Path file) { @FxThread public void notifyDeleted(@NotNull Path file) { - var element = createFor(file); - var treeItem = findItemForValue(getRoot(), element); + var element = ResourceElementFactory.createFor(file); + var treeItem = UiUtils.findItemForValue(getRoot(), element); if (treeItem == null) { return; } @@ -865,14 +852,14 @@ public void notifyDeleted(@NotNull Path file) { @FxThread public void notifyMoved(@NotNull Path prevFile, @NotNull Path newFile) { - var prevElement = createFor(prevFile); - var prevItem = findItemForValue(getRoot(), prevElement); + var prevElement = ResourceElementFactory.createFor(prevFile); + var prevItem = UiUtils.findItemForValue(getRoot(), prevElement); if (prevItem == null) { return; } - var newParentElement = createFor(newFile.getParent()); - var newParentItem = findItemForValue(getRoot(), newParentElement); + var newParentElement = ResourceElementFactory.createFor(newFile.getParent()); + var newParentItem = UiUtils.findItemForValue(getRoot(), newParentElement); if (newParentItem == null) { return; } @@ -881,7 +868,7 @@ public void notifyMoved(@NotNull Path prevFile, @NotNull Path newFile) { var prevParentChildren = prevParentItem.getChildren(); prevParentChildren.remove(prevItem); - prevItem.setValue(createFor(newFile)); + prevItem.setValue(ResourceElementFactory.createFor(newFile)); var children = UiUtils.getAllItems(prevItem); children.fastRemove(prevItem); @@ -908,7 +895,7 @@ private void fillChildren( var relativeFile = file.subpath(prevFile.getNameCount(), file.getNameCount()); var resultFile = newFile.resolve(relativeFile); - child.setValue(createFor(resultFile)); + child.setValue(ResourceElementFactory.createFor(resultFile)); } } @@ -921,13 +908,13 @@ private void fillChildren( @FxThread public void notifyRenamed(@NotNull Path prevFile, @NotNull Path newFile) { - var prevElement = createFor(prevFile); - var prevItem = findItemForValue(getRoot(), prevElement); + var prevElement = ResourceElementFactory.createFor(prevFile); + var prevItem = UiUtils.findItemForValue(getRoot(), prevElement); if (prevItem == null) { return; } - prevItem.setValue(createFor(newFile)); + prevItem.setValue(ResourceElementFactory.createFor(newFile)); var children = UiUtils.getAllItems(prevItem); children.fastRemove(prevItem); @@ -1010,7 +997,7 @@ private void processKey(@NotNull KeyEvent event) { } } - if (controlDown && keyCode == KeyCode.V && hasFileInClipboard() && + if (controlDown && keyCode == KeyCode.V && UiUtils.hasFileInClipboard() && actionTester.test(PasteFileAction.class)) { PasteFileAction.applyFor(firstElement); @@ -1080,8 +1067,8 @@ public void expandTo(@NotNull TreeItem treeItem, boolean needSe @FxThread public void markExpand(@NotNull Path file) { - var element = createFor(file); - var treeItem = findItemForValue(getRoot(), element); + var element = ResourceElementFactory.createFor(file); + var treeItem = UiUtils.findItemForValue(getRoot(), element); if (treeItem == null) { return; } @@ -1120,7 +1107,7 @@ public void expandTo(@NotNull Path file, boolean needSelect) { if (isLazyMode()) { - var targetItem = findItemForValue(getRoot(), file); + var targetItem = UiUtils.findItemForValue(getRoot(), file); if (targetItem == null) { TreeItem parentItem = null; @@ -1128,7 +1115,7 @@ public void expandTo(@NotNull Path file, boolean needSelect) { var parent = file.getParent(); while (parent != null) { - parentItem = findItemForValue(getRoot(), parent); + parentItem = UiUtils.findItemForValue(getRoot(), parent); if (parentItem != null) { break; } @@ -1152,8 +1139,8 @@ public void expandTo(@NotNull Path file, boolean needSelect) { } } - var element = createFor(file); - var treeItem = findItemForValue(getRoot(), element); + var element = ResourceElementFactory.createFor(file); + var treeItem = UiUtils.findItemForValue(getRoot(), element); if (treeItem == null) { return; } diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTreeCell.java b/src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTreeCell.java similarity index 83% rename from src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTreeCell.java rename to src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTreeCell.java index e0957416..3800948c 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTreeCell.java +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/ResourceTreeCell.java @@ -1,13 +1,19 @@ -package com.ss.editor.ui.component.asset.tree; +package com.ss.builder.fx.component.asset.tree; -import static com.ss.editor.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE; +import static com.ss.builder.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE; import static java.util.Collections.singletonList; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.FileIconManager; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.component.asset.tree.resource.FolderResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.LoadingResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.LoadingResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.LoadingResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; import com.ss.rlib.common.util.StringUtils; import javafx.geometry.Side; import javafx.scene.Cursor; @@ -151,7 +157,7 @@ protected void updateItem(@Nullable ResourceElement item, boolean empty) { var fileName = file.getFileName(); var folder = item instanceof FolderResourceElement; - icon.setImage(ICON_MANAGER.getIcon(file, folder, true, DEFAULT_FILE_ICON_SIZE)); + icon.setImage(ICON_MANAGER.getIcon(file, folder, true, FileIconManager.DEFAULT_FILE_ICON_SIZE)); setText(fileName == null ? file.toString() : fileName.toString()); setGraphic(icon); diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileAction.java new file mode 100644 index 00000000..db7d785b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileAction.java @@ -0,0 +1,34 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.Messages; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import com.ss.rlib.common.util.array.Array; + +/** + * The action to transformation a file. + * + * @author JavaSaBr + */ +public class ConvertFileAction extends Menu { + + public ConvertFileAction(@NotNull final ResourceElement element, + @NotNull final Array descriptions) { + + setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_CONVERT_FILE); + setGraphic(new ImageView(Icons.TRANSFORMATION_16)); + + final ObservableList items = getItems(); + descriptions.forEach(description -> items.add(new ConvertFileByConverterAction(element, description))); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java new file mode 100644 index 00000000..6eb60025 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedConvertFileEvent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedConvertFileEvent; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to transformation a file by a transformer. + * + * @author JavaSaBr + */ +public class ConvertFileByConverterAction extends FileAction { + + /** + * The transformer description. + */ + @NotNull + private final FileConverterDescription description; + + public ConvertFileByConverterAction( + @NotNull ResourceElement element, + @NotNull FileConverterDescription description + ) { + super(element); + this.description = description; + setText(description.getDescription()); + } + + @FxThread + @Override + protected @Nullable Image getIcon() { + return Icons.TRANSFORMATION_16; + } + + @FxThread + @Override + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + FxEventManager.getInstance() + .notify(new RequestedConvertFileEvent(description, getFile())); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CopyFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CopyFileAction.java new file mode 100644 index 00000000..f4ea00f1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CopyFileAction.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The action to copy a file. + * + * @author JavaSaBr + */ +public class CopyFileAction extends FileAction { + + @FxThread + public static void applyFor(@NotNull Array elements) { + new CopyFileAction(elements).getOnAction().handle(null); + } + + public CopyFileAction(@NotNull Array elements) { + super(elements); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_COPY_FILE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.COPY_16; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + var files = getElements().stream() + .map(ResourceElement::getFile) + .collect(toArray(Path.class)); + + var clipboard = Clipboard.getSystemClipboard(); + clipboard.setContent(EditorUtils.addCopiedFile(files, new ClipboardContent())); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CutFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CutFileAction.java new file mode 100644 index 00000000..7bede68f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/CutFileAction.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import static java.util.stream.Collectors.toList; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The action to cut a file. + * + * @author JavaSaBr + */ +public class CutFileAction extends FileAction { + + @FxThread + public static void applyFor(@NotNull Array elements) { + new CutFileAction(elements).getOnAction().handle(null); + } + + public CutFileAction(@NotNull Array elements) { + super(elements); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.CUT_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_CUT_FILE; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + var files = getElements().stream() + .map(ResourceElement::getFile) + .map(Path::toFile) + .collect(toList()); + + var content = new ClipboardContent(); + content.putFiles(files); + content.put(EditorUtils.JAVA_PARAM, "cut"); + + var clipboard = Clipboard.getSystemClipboard(); + clipboard.setContent(content); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/DeleteFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/DeleteFileAction.java new file mode 100644 index 00000000..7c33bf82 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/DeleteFileAction.java @@ -0,0 +1,107 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.file.handler.delete.FileDeleteHandler; +import com.ss.builder.file.handler.delete.FileDeleteHandlerFactory; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The action for deleting a file. + * + * @author JavaSaBr + */ +public class DeleteFileAction extends FileAction { + + @FxThread + public static void applyFor(@NotNull Array elements) { + new DeleteFileAction(elements) + .getOnAction() + .handle(null); + } + + public DeleteFileAction(@NotNull Array elements) { + super(elements); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + var elements = getElements(); + + if(elements.size() == 1) { + + var first = notNull(elements.first()); + var file = first.getFile(); + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + if (currentAsset == null || currentAsset.equals(file)) { + return; + } + + var question = Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILE_QUESTION; + question = question.replace("%file_name%", file.getFileName().toString()); + + ConfirmDialog.ifOk(question, () -> deleteFile(file)); + + } else { + + var question = Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILES_QUESTION; + question = question.replace("%file_count%", String.valueOf(elements.size())); + + ConfirmDialog.ifOk(question, () -> deleteFiles(elements)); + } + } + + @FxThread + private void deleteFile(@NotNull Path file) { + + var handlers = FileDeleteHandlerFactory.findFor(file); + handlers.forEach(file, FileDeleteHandler::preDelete); + + FileUtils.delete(file); + + handlers.forEach(file, FileDeleteHandler::postDelete); + } + + @FxThread + private void deleteFiles(@NotNull Array elements) { + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + if (currentAsset == null) { + return; + } + + elements.stream().map(ResourceElement::getFile) + .filter(path -> !currentAsset.equals(path)) + .forEach(this::deleteFile); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/FileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/FileAction.java new file mode 100644 index 00000000..298e141e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/FileAction.java @@ -0,0 +1,120 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.array.Array; +import javafx.event.ActionEvent; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The base implementation of a file action. + * + * @author JavaSaBr + */ +public class FileAction extends MenuItem { + + protected static final Logger LOGGER = LoggerManager.getLogger(FileAction.class); + + /** + * The action element. + */ + @Nullable + private final ResourceElement element; + + /** + * The action elements. + */ + @Nullable + private final Array elements; + + public FileAction(@NotNull ResourceElement element) { + this(element, null); + } + + public FileAction(@NotNull Array elements) { + this(null, elements); + } + + public FileAction(@Nullable ResourceElement element, @Nullable Array elements) { + this.element = element; + this.elements = elements; + + setText(getName()); + setOnAction(this::execute); + + Image icon = getIcon(); + if (icon != null) { + setGraphic(new ImageView(icon)); + } + } + + /** + * Get the file element of this action. + * + * @return the file element. + */ + @FxThread + protected @NotNull ResourceElement getElement() { + return notNull(element); + } + + /** + * Get a file of the current resource element. + * + * @return the file of the current resource element. + */ + @FxThread + protected @NotNull Path getFile() { + return getElement().getFile(); + } + + /** + * Get the file elements of this action. + * + * @return the file elements. + */ + @FxThread + protected @NotNull Array getElements() { + return notNull(elements); + } + + /** + * Get an icon of this action. + * + * @return the icon or null. + */ + @FxThread + protected @Nullable Image getIcon() { + return null; + } + + /** + * Handle executing of this action. + * + * @param event the event. + */ + @FxThread + protected void execute(@Nullable ActionEvent event) { + } + + /** + * Get the name of this action. + * + * @return the name. + */ + @FxThread + protected @NotNull String getName() { + return "Unknown"; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ImportModelFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ImportModelFileAction.java new file mode 100644 index 00000000..04fda17e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/ImportModelFileAction.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.FileResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.FileResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.dialog.imports.model.ModelImportDialog; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to import an model to current asset folder. + * + * @author JavaSaBr + */ +public class ImportModelFileAction extends FileAction { + + public ImportModelFileAction(@NotNull final ResourceElement element) { + super(element); + } + + @FxThread + @Override + protected void execute(@Nullable final ActionEvent event) { + super.execute(event); + + final ResourceElement element = getElement(); + + final ModelImportDialog dialog = new ModelImportDialog(); + if (element instanceof FileResourceElement) { + dialog.start(element.getFile().getParent()); + } else { + dialog.start(element.getFile()); + } + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_IMPORT_MODEL; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.IMPORT_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileAction.java new file mode 100644 index 00000000..0be19742 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileAction.java @@ -0,0 +1,32 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.creator.FileCreatorRegistry; +import com.ss.builder.Messages; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.creator.FileCreatorRegistry; +import javafx.scene.control.Menu; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create a new file. + * + * @author JavaSaBr + */ +public class NewFileAction extends Menu { + + public NewFileAction(@NotNull ResourceElement element) { + setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_NEW_FILE); + setGraphic(new ImageView(Icons.NEW_FILE_16)); + + var items = getItems(); + + FileCreatorRegistry.getInstance() + .getDescriptors() + .forEach(description -> items.add(new NewFileByCreatorAction(element, description))); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileByCreatorAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileByCreatorAction.java new file mode 100644 index 00000000..b8c9b3ce --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/NewFileByCreatorAction.java @@ -0,0 +1,52 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedCreateFileEvent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedCreateFileEvent; +import javafx.event.ActionEvent; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action for creating a new file. + * + * @author JavaSaBr + */ +class NewFileByCreatorAction extends FileAction { + + /** + * The creator descriptor. + */ + @NotNull + private final FileCreatorDescriptor descriptor; + + public NewFileByCreatorAction(@NotNull ResourceElement element, @NotNull FileCreatorDescriptor descriptor) { + super(element); + + this.descriptor = descriptor; + + var icon = descriptor.getIcon(); + + setText(descriptor.getDescription()); + setGraphic(new ImageView(icon == null ? Icons.NEW_FILE_16 : icon)); + } + + @FxThread + @Override + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + FxEventManager.getInstance() + .notify(new RequestedCreateFileEvent(getElement().getFile(), descriptor)); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileAction.java new file mode 100644 index 00000000..c9916c4a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileAction.java @@ -0,0 +1,42 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedOpenFileEvent; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedOpenFileEvent; +import javafx.event.ActionEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to open a file. + * + * @author JavaSaBr + */ +public class OpenFileAction extends FileAction { + + public OpenFileAction(@NotNull ResourceElement element) { + super(element); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + FxEventManager.getInstance() + .notify(new RequestedOpenFileEvent(getFile())); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByEditorAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByEditorAction.java new file mode 100644 index 00000000..2db7b10e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByEditorAction.java @@ -0,0 +1,55 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedOpenFileEvent; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to open a file by an editor. + * + * @author JavaSaBr + */ +class OpenFileByEditorAction extends FileAction { + + /** + * The editor description. + */ + @NotNull + private final EditorDescriptor description; + + public OpenFileByEditorAction(@NotNull ResourceElement element, @NotNull EditorDescriptor description) { + super(element); + this.description = description; + + setText(description.getEditorName()); + + var icon = description.getIcon(); + + if (icon != null) { + setGraphic(new ImageView(icon)); + } + } + + @FxThread + @Override + protected @Nullable Image getIcon() { + return Icons.EDIT_16; + } + + @FxThread + @Override + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + FxEventManager.getInstance() + .notify(new RequestedOpenFileEvent(getFile(), description)); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java new file mode 100644 index 00000000..3b099b91 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to open a file in an external editor. + * + * @author JavaSaBr + */ +public class OpenFileByExternalEditorAction extends FileAction { + + public OpenFileByExternalEditorAction(@NotNull final ResourceElement element) { + super(element); + } + + @FxThread + @Override + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE_BY_EXTERNAL_EDITOR; + } + + @FxThread + @Override + protected @Nullable Image getIcon() { + return Icons.EDIT_2_16; + } + + @FxThread + @Override + protected void execute(@Nullable final ActionEvent event) { + super.execute(event); + EditorUtils.openFileInExternalEditor(getElement().getFile()); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java new file mode 100644 index 00000000..c37c7429 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.util.EditorUtils; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to open a file in an system explorer. + * + * @author JavaSaBr + */ +public class OpenFileInExplorerAction extends FileAction { + + public OpenFileInExplorerAction(@NotNull final ResourceElement element) { + super(element); + } + + @FxThread + @Override + protected @Nullable Image getIcon() { + return Icons.EXPLORER_16; + } + + @FxThread + @Override + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE_BY_SYSTEM_EXPLORER; + } + + @FxThread + @Override + protected void execute(@Nullable final ActionEvent event) { + super.execute(event); + EditorUtils.openFileInSystemExplorer(getElement().getFile()); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenWithFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenWithFileAction.java new file mode 100644 index 00000000..9d5ef08f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/OpenWithFileAction.java @@ -0,0 +1,44 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.EditorRegistry; + +import org.jetbrains.annotations.NotNull; + +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import com.ss.rlib.common.util.array.Array; + +/** + * The action to choose an editor to open a file. + * + * @author JavaSaBr + */ +public class OpenWithFileAction extends Menu { + + private static final EditorRegistry EDITOR_REGISTRY = EditorRegistry.getInstance(); + + /** + * The action element. + */ + @NotNull + private final ResourceElement element; + + /** + * Instantiates a new Open with file action. + * + * @param element the element + */ + public OpenWithFileAction(@NotNull final ResourceElement element) { + this.element = element; + setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_WITH_FILE); + + final ObservableList items = getItems(); + + final Array descriptions = EDITOR_REGISTRY.getAvailableEditorsFor(element.getFile()); + descriptions.forEach(description -> items.add(new OpenFileByEditorAction(element, description))); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/PasteFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/PasteFileAction.java new file mode 100644 index 00000000..0d3497de --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/PasteFileAction.java @@ -0,0 +1,195 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.MovedFileEvent; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.MovedFileEvent; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import javafx.scene.input.Clipboard; +import javafx.scene.input.DataFormat; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +/** + * The action to paste a file. + * + * @author JavaSaBr + */ +public class PasteFileAction extends FileAction { + + @FxThread + public static void applyFor(@NotNull ResourceElement element) { + new PasteFileAction(element).getOnAction().handle(null); + } + + public PasteFileAction(@NotNull ResourceElement element) { + super(element); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_PASTE_FILE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PASTE_16; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + var clipboard = Clipboard.getSystemClipboard(); + if (clipboard == null) { + return; + } + + var files = ClassUtils.>unsafeCast(clipboard.getContent(DataFormat.FILES)); + if (files == null || files.isEmpty()) { + return; + } + + var currentFile = getElement().getFile(); + var isCut = "cut".equals(clipboard.getContent(EditorUtils.JAVA_PARAM)); + + if (isCut) { + files.forEach(file -> moveFile(currentFile, file.toPath())); + } else { + files.forEach(file -> copyFile(currentFile, file.toPath())); + } + + clipboard.clear(); + } + + private void copyFile(@NotNull Path currentFile, @NotNull Path file) { + if (Files.isDirectory(currentFile)) { + processCopy(currentFile, file); + } else { + processCopy(currentFile.getParent(), file); + } + } + + private void moveFile(@NotNull Path currentFile, @NotNull Path file) { + if (Files.isDirectory(currentFile)) { + processMove(currentFile, file); + } else { + processMove(currentFile.getParent(), file); + } + } + + /** + * Process of moving. + */ + private void processMove(@NotNull Path targetFolder, @NotNull Path file) { + + var newFile = targetFolder.resolve(file.getFileName()); + + try { + Files.move(file, newFile); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + FxEventManager.getInstance() + .notify(new MovedFileEvent(file, newFile)); + } + + /** + * Process of copying. + */ + private void processCopy(@NotNull Path targetFolder, @NotNull Path file) { + + var toCopy = Array.ofType(Path.class); + var copied = Array.ofType(Path.class); + + if (Files.isDirectory(file)) { + toCopy.addAll(FileUtils.getFiles(file, true)); + toCopy.sort(FileUtils.FILE_PATH_LENGTH_COMPARATOR); + toCopy.slowRemove(file); + } + + var freeName = FileUtils.getFirstFreeName(targetFolder, file); + var newFile = targetFolder.resolve(freeName); + + try { + processCopy(file, toCopy, copied, newFile); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + FxEventManager.getInstance() + .notify(new RequestSelectFileEvent(newFile)); + } + + /** + * Process of copying. + */ + private void processCopy( + @NotNull Path file, + @NotNull Array toCopy, + @NotNull Array copied, + @NotNull Path newFile + ) throws IOException { + + Files.copy(file, newFile); + + copied.add(newFile); + toCopy.forEach(path -> { + + var relativeFile = file.relativize(path); + var targetFile = newFile.resolve(relativeFile); + + try { + Files.copy(path, targetFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + + var needAddToCopied = true; + + for (var copiedFile : copied) { + + if (!Files.isDirectory(copiedFile)) { + continue; + } + + if (targetFile.startsWith(copiedFile)) { + needAddToCopied = false; + break; + } + } + + if (needAddToCopied) { + copied.add(targetFile); + } + }); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/RenameFileAction.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/RenameFileAction.java new file mode 100644 index 00000000..4552fdde --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/action/RenameFileAction.java @@ -0,0 +1,106 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.action; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.dialog.RenameDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RenamedFileEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.dialog.RenameDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RenamedFileEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import javafx.event.ActionEvent; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; + +/** + * The action to rename a file. + * + * @author JavaSaBr + */ +public class RenameFileAction extends FileAction { + + public RenameFileAction(@NotNull ResourceElement element) { + super(element); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.EDIT_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_RENAME_FILE; + } + + @Override + @FxThread + protected void execute(@Nullable ActionEvent event) { + super.execute(event); + + var file = getFile(); + + var renameDialog = new RenameDialog(); + renameDialog.setValidator(this::checkName); + renameDialog.setHandler(this::processRename); + renameDialog.setInitName(FileUtils.getNameWithoutExtension(file)); + renameDialog.show(); + } + + /** + * The checking of the new file name. + */ + private Boolean checkName(@NotNull String newFileName) { + + if (!FileUtils.isValidName(newFileName)) { + return false; + } + + var file = getElement().getFile(); + var extension = FileUtils.getExtension(file); + + var parent = file.getParent(); + var targetFile = parent.resolve(StringUtils.isEmpty(extension) ? newFileName : newFileName + "." + extension); + + return !Files.exists(targetFile); + } + + /** + * The process of renaming. + */ + private void processRename(@NotNull String newFileName) { + + var file = getFile(); + + var extension = FileUtils.getExtension(file); + var resultName = StringUtils.isEmpty(extension) ? newFileName : newFileName + "." + extension; + + var newFile = file.resolveSibling(resultName); + + try { + Files.move(file, newFile); + } catch (IOException e) { + EditorUtils.handleException(null, this, e); + return; + } + + FxEventManager.getInstance() + .notify(new RenamedFileEvent(file, newFile)); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java new file mode 100644 index 00000000..e0a90dbb --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java @@ -0,0 +1,32 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.filler; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.control.MenuItem; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.function.Predicate; + +/** + * The interface to implement a context menu filler for multiply elements. + * + * @author JavaSaBr + */ +@FunctionalInterface +public interface AssetTreeMultiContextMenuFiller { + + /** + * Fill the context menu of the resource element. + * + * @param elements the list of resource elements. + * @param items the container of items of a context menu. + * @param actionTester the action tester. + */ + @FxThread + void fill(@NotNull final Array elements, @NotNull final List items, + @NotNull final Predicate> actionTester); +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java new file mode 100644 index 00000000..21025334 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java @@ -0,0 +1,34 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.filler; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import javafx.scene.control.MenuItem; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.function.Predicate; + +/** + * The interface to implement a context menu filler. + * + * @author JavaSaBr + */ +@FunctionalInterface +public interface AssetTreeSingleContextMenuFiller { + + /** + * Fill the context menu of the resource element. + * + * @param element the resource element. + * @param items the container of items of a context menu. + * @param actionTester the action tester. + */ + @FxThread + void fill( + @NotNull ResourceElement element, + @NotNull List items, + @NotNull Predicate> actionTester + ); +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java new file mode 100644 index 00000000..0febc08b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java @@ -0,0 +1,72 @@ +package com.ss.builder.fx.component.asset.tree.context.menu.filler.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.file.converter.FileConverterRegistry; +import com.ss.builder.fx.component.asset.tree.resource.FileResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.file.converter.FileConverterRegistry; +import com.ss.builder.fx.component.asset.tree.context.menu.action.*; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.resource.FileResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.control.MenuItem; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.List; +import java.util.function.Predicate; + +/** + * The implementation a filler to create actions for files. + * + * @author JavaSaBr + */ +public class FileAssetTreeSingleContextMenuFiller implements AssetTreeSingleContextMenuFiller, + AssetTreeMultiContextMenuFiller { + + @NotNull + private static final FileConverterRegistry FILE_CONVERTER_REGISTRY = FileConverterRegistry.getInstance(); + + @Override + @FxThread + public void fill(@NotNull final ResourceElement element, @NotNull final List items, + @NotNull final Predicate> actionTester) { + + if (element instanceof FileResourceElement) { + + if (actionTester.test(OpenFileAction.class)) { + items.add(new OpenFileAction(element)); + } + + if (actionTester.test(OpenWithFileAction.class)) { + items.add(new OpenWithFileAction(element)); + } + + + if (actionTester.test(ConvertFileAction.class)) { + + final Path file = element.getFile(); + final Array descriptions = FILE_CONVERTER_REGISTRY.getDescriptions(file); + + if (!descriptions.isEmpty()) { + items.add(new ConvertFileAction(element, descriptions)); + } + } + + if (actionTester.test(OpenFileByExternalEditorAction.class)) { + items.add(new OpenFileByExternalEditorAction(element)); + } + } + } + + @Override + @FxThread + public void fill(@NotNull final Array elements, @NotNull final List items, + @NotNull final Predicate> actionTester) { + } +} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java similarity index 79% rename from src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java rename to src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java index 685436c6..681e5e42 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java +++ b/src/main/java/com/ss/builder/fx/component/asset/tree/context/menu/filler/impl/ResourceAssetTreeSingleContextMenuFiller.java @@ -1,14 +1,14 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.filler.impl; - -import static com.ss.editor.ui.util.UiUtils.hasFileInClipboard; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.asset.tree.context.menu.action.*; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.resource.FileResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.FolderResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; +package com.ss.builder.fx.component.asset.tree.context.menu.filler.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.component.asset.tree.context.menu.action.*; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; +import com.ss.builder.fx.component.asset.tree.resource.FileResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.util.array.Array; import javafx.scene.control.MenuItem; import org.jetbrains.annotations.NotNull; @@ -43,7 +43,7 @@ public void fill(@NotNull final ResourceElement element, @NotNull final List process()); + } + + /** + * Open the dialog. + */ + private void process() { + final AboutDialog dialog = new AboutDialog(); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/bar/action/ClearAssetCacheAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/ClearAssetCacheAction.java new file mode 100644 index 00000000..561b5b30 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/bar/action/ClearAssetCacheAction.java @@ -0,0 +1,36 @@ +package com.ss.builder.fx.component.bar.action; + +import com.jme3.asset.AssetManager; +import com.ss.builder.Messages; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import javafx.scene.control.MenuItem; + +/** + * The action to clean asset cache. + * + * @author JavaSaBr + */ +public class ClearAssetCacheAction extends MenuItem { + + /** + * Instantiates a new ClearAssetCacheAction. + */ + public ClearAssetCacheAction() { + super(Messages.EDITOR_MENU_OTHER_CLEAR_ASSET_CACHE); + setOnAction(event -> process()); + } + + /** + * Clear asset cache. + */ + private void process() { + ExecutorManager.getInstance().addJmeTask(() -> { + final AssetManager assetManager = EditorUtils.getAssetManager(); + assetManager.clearCache(); + }); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/ExitAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/ExitAction.java similarity index 80% rename from src/main/java/com/ss/editor/ui/component/bar/action/ExitAction.java rename to src/main/java/com/ss/builder/fx/component/bar/action/ExitAction.java index 3815cfe7..66dadfa7 100644 --- a/src/main/java/com/ss/editor/ui/component/bar/action/ExitAction.java +++ b/src/main/java/com/ss/builder/fx/component/bar/action/ExitAction.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.component.bar.action; +package com.ss.builder.fx.component.bar.action; -import com.ss.editor.Messages; +import com.ss.builder.Messages; +import com.ss.builder.Messages; import javafx.application.Platform; import javafx.scene.control.MenuItem; diff --git a/src/main/java/com/ss/builder/fx/component/bar/action/OpenAssetAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/OpenAssetAction.java new file mode 100644 index 00000000..76cb66c5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/bar/action/OpenAssetAction.java @@ -0,0 +1,134 @@ +package com.ss.builder.fx.component.bar.action; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_NATIVE_FILE_CHOOSER; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_NATIVE_FILE_CHOOSER; +import com.ss.builder.Messages; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.dialog.file.chooser.OpenExternalFolderEditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.dialog.file.chooser.OpenExternalFolderEditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.util.EditorUtils; +import javafx.scene.control.MenuItem; +import javafx.stage.DirectoryChooser; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The action to open a new asset folder. + * + * @author JavaSaBr + */ +public class OpenAssetAction extends MenuItem { + + @NotNull + private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); + + public OpenAssetAction() { + super(Messages.EDITOR_MENU_FILE_OPEN_ASSET); + setOnAction(event -> process()); + } + + /** + * The process of selecting an asset folder. + */ + @FxThread + private void process() { + + final EditorConfig config = EditorConfig.getInstance(); + + if (config.getBoolean(DefaultSettingsProvider.Preferences.PREF_NATIVE_FILE_CHOOSER, DefaultSettingsProvider.Defaults.PREF_DEFAULT_NATIVE_FILE_CHOOSER)) { + openAssetByNative(); + } else { + openAsset(); + } + } + + /** + * Open asset folder using native file chooser. + */ + @FxThread + private void openAssetByNative() { + + final DirectoryChooser chooser = new DirectoryChooser(); + chooser.setTitle(Messages.EDITOR_MENU_FILE_OPEN_ASSET_DIRECTORY_CHOOSER); + + final EditorConfig config = EditorConfig.getInstance(); + final Path currentAsset = config.getCurrentAsset(); + final File currentFolder = currentAsset == null ? null : currentAsset.toFile(); + + if (currentFolder == null) { + chooser.setInitialDirectory(new File(System.getProperty("user.home"))); + } else { + chooser.setInitialDirectory(currentFolder); + } + + GAnalytics.sendPageView("AssetChooseDialog", null, "/dialog/AssetChooseDialog"); + GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_OPENED, "AssetChooseDialog"); + + final File folder = chooser.showDialog(EditorUtils.getFxLastWindow()); + + GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_CLOSED, "AssetChooseDialog"); + + if (folder == null) { + return; + } + + openAssetFolder(folder.toPath()); + } + + /** + * Open an asset folder using custom file chooser. + */ + @FxThread + private void openAsset() { + + final OpenExternalFolderEditorDialog dialog = new OpenExternalFolderEditorDialog(this::openAssetFolder); + dialog.setTitleText(Messages.EDITOR_MENU_FILE_OPEN_ASSET_DIRECTORY_CHOOSER); + + final EditorConfig config = EditorConfig.getInstance(); + final Path currentAsset = config.getCurrentAsset(); + + if (currentAsset == null) { + dialog.setInitDirectory(Paths.get(System.getProperty("user.home"))); + } else { + dialog.setInitDirectory(currentAsset); + } + + dialog.show(); + } + + /** + * Open the asset folder. + * + * @param newAsset the asset folder. + */ + @FxThread + public void openAssetFolder(@NotNull final Path newAsset) { + + final EditorConfig config = EditorConfig.getInstance(); + final Path currentAsset = config.getCurrentAsset(); + if (newAsset.equals(currentAsset)) return; + + config.addOpenedAsset(newAsset); + config.setCurrentAsset(newAsset); + config.save(); + + FX_EVENT_MANAGER.notify(new ChangedCurrentAssetFolderEvent(newAsset)); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/bar/action/OpenPluginsAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/OpenPluginsAction.java new file mode 100644 index 00000000..8faef437 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/bar/action/OpenPluginsAction.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.component.bar.action; + +import com.ss.builder.Messages; +import com.ss.builder.Messages; +import com.ss.builder.fx.dialog.plugin.PluginsDialog; +import javafx.scene.control.MenuItem; + +/** + * The action to open plugins dialog. + * + * @author JavaSaBr + */ +public class OpenPluginsAction extends MenuItem { + + public OpenPluginsAction() { + super(Messages.EDITOR_MENU_OTHER_PLUGINS); + setOnAction(event -> process()); + } + + /** + * Open the plugin dialog. + */ + private void process() { + new PluginsDialog().show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/bar/action/OpenSettingsAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/OpenSettingsAction.java new file mode 100644 index 00000000..01b24a23 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/bar/action/OpenSettingsAction.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.component.bar.action; + +import com.ss.builder.Messages; +import com.ss.builder.fx.dialog.SettingsDialog; +import com.ss.builder.Messages; +import com.ss.builder.fx.dialog.SettingsDialog; +import javafx.scene.control.MenuItem; + +/** + * The action to open the dialog with settings. + * + * @author JavaSaBr + */ +public class OpenSettingsAction extends MenuItem { + + public OpenSettingsAction() { + super(Messages.EDITOR_MENU_OTHER_SETTINGS); + setOnAction(event -> process()); + } + + /** + * Open the dialog. + */ + private void process() { + new SettingsDialog().show(); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetAction.java similarity index 78% rename from src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetAction.java rename to src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetAction.java index 0d10b903..aedf763a 100644 --- a/src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetAction.java +++ b/src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetAction.java @@ -1,8 +1,11 @@ -package com.ss.editor.ui.component.bar.action; +package com.ss.builder.fx.component.bar.action; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; import javafx.scene.control.MenuItem; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetMenu.java b/src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetMenu.java similarity index 75% rename from src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetMenu.java rename to src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetMenu.java index f1c06c6a..aa3bb60f 100644 --- a/src/main/java/com/ss/editor/ui/component/bar/action/ReopenAssetMenu.java +++ b/src/main/java/com/ss/builder/fx/component/bar/action/ReopenAssetMenu.java @@ -1,9 +1,13 @@ -package com.ss.editor.ui.component.bar.action; - -import com.ss.editor.Messages; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.ChangedCurrentAssetFolderEvent; +package com.ss.builder.fx.component.bar.action; + +import com.ss.builder.Messages; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.Messages; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; import javafx.collections.ObservableList; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; diff --git a/src/main/java/com/ss/builder/fx/component/bar/action/UpdateClasspathAndAssetCacheAction.java b/src/main/java/com/ss/builder/fx/component/bar/action/UpdateClasspathAndAssetCacheAction.java new file mode 100644 index 00000000..4a5c1bd7 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/bar/action/UpdateClasspathAndAssetCacheAction.java @@ -0,0 +1,42 @@ +package com.ss.builder.fx.component.bar.action; + +import com.jme3.asset.AssetManager; +import com.ss.builder.Messages; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import javafx.scene.control.MenuItem; + +/** + * The action to update a user classpath and to clear asset cache. + * + * @author JavaSaBr + */ +public class UpdateClasspathAndAssetCacheAction extends MenuItem { + + /** + * Instantiates a new UpdateClasspathAndAssetCacheAction. + */ + public UpdateClasspathAndAssetCacheAction() { + super(Messages.EDITOR_MENU_OTHER_UPDATE_CLASSPATH_AND_ASSET_CACHE); + setOnAction(event -> process()); + } + + /** + * Update classpath and clear asset cache. + */ + private void process() { + ExecutorManager.getInstance().addJmeTask(() -> { + + final ClasspathManager classpathManager = ClasspathManager.getInstance(); + classpathManager.reload(); + + final AssetManager assetManager = EditorUtils.getAssetManager(); + assetManager.clearCache(); + }); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/FileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/FileCreator.java new file mode 100644 index 00000000..709e2658 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/FileCreator.java @@ -0,0 +1,23 @@ +package com.ss.builder.fx.component.creator; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The interface to implement a some file creator. + * + * @author JavaSaBr + */ +public interface FileCreator { + + /** + * Start creating a new file. + * + * @param file the parent or nearest file. + */ + @FxThread + void start(@NotNull Path file); +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/FileCreatorDescriptor.java b/src/main/java/com/ss/builder/fx/component/creator/FileCreatorDescriptor.java new file mode 100644 index 00000000..b4f6b149 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/FileCreatorDescriptor.java @@ -0,0 +1,89 @@ +package com.ss.builder.fx.component.creator; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.Callable; + +/** + * The descriptor of a file creator. + * + * @author JavaSaBr + */ +public class FileCreatorDescriptor { + + /** + * The description. + */ + @NotNull + private final String description; + + /** + * The constructor. + */ + @NotNull + private final Callable constructor; + + /** + * The icon. + */ + @Nullable + private final Image icon; + + public FileCreatorDescriptor(@Nullable String description, @NotNull Callable constructor) { + this(description, constructor, null); + } + + public FileCreatorDescriptor( + @Nullable String description, + @NotNull Callable constructor, + @Nullable Image icon + ) { + this.description = StringUtils.emptyIfNull(description); + this.constructor = constructor; + this.icon = icon; + } + + /** + * Get the constructor. + * + * @return the constructor. + */ + @FromAnyThread + public @NotNull Callable getConstructor() { + return notNull(constructor); + } + + /** + * Get the description. + * + * @return the description. + */ + @FromAnyThread + public @NotNull String getDescription() { + return description; + } + + /** + * Get the icon. + * + * @return the icon or null. + */ + @FromAnyThread + public @Nullable Image getIcon() { + return icon; + } + + @Override + public String toString() { + return "FileCreatorDescriptor{" + + "description='" + description + '\'' + + ", constructor=" + constructor + + '}'; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/FileCreatorRegistry.java b/src/main/java/com/ss/builder/fx/component/creator/FileCreatorRegistry.java new file mode 100644 index 00000000..2f72bcbf --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/FileCreatorRegistry.java @@ -0,0 +1,108 @@ +package com.ss.builder.fx.component.creator; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.creator.impl.EmptyFileCreator; +import com.ss.builder.fx.component.creator.impl.EmptyModelCreator; +import com.ss.builder.fx.component.creator.impl.EmptySceneCreator; +import com.ss.builder.fx.component.creator.impl.FolderCreator; +import com.ss.builder.fx.component.creator.impl.material.MaterialFileCreator; +import com.ss.builder.fx.component.creator.impl.material.definition.MaterialDefinitionFileCreator; +import com.ss.builder.fx.component.creator.impl.texture.SingleColorTextureFileCreator; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.creator.impl.EmptyFileCreator; +import com.ss.builder.fx.component.creator.impl.EmptyModelCreator; +import com.ss.builder.fx.component.creator.impl.EmptySceneCreator; +import com.ss.builder.fx.component.creator.impl.FolderCreator; +import com.ss.builder.fx.component.creator.impl.material.MaterialFileCreator; +import com.ss.builder.fx.component.creator.impl.material.definition.MaterialDefinitionFileCreator; +import com.ss.builder.fx.component.creator.impl.texture.SingleColorTextureFileCreator; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +/** + * The registry of available file creators. + * + * @author JavaSaBr + */ +public class FileCreatorRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(FileCreatorRegistry.class); + + /** + * @see FileCreatorDescriptor + */ + public static final String EP_DESCRIPTORS = "FileCreatorRegistry#descriptors"; + + private static final ExtensionPoint DESCRIPTORS = + ExtensionPointManager.register(EP_DESCRIPTORS); + + private static final FileCreatorRegistry INSTANCE = new FileCreatorRegistry(); + + @FromAnyThread + public @NotNull static FileCreatorRegistry getInstance() { + return INSTANCE; + } + + private FileCreatorRegistry() { + + DESCRIPTORS.register(MaterialFileCreator.DESCRIPTOR) + .register(MaterialDefinitionFileCreator.DESCRIPTOR) + .register(EmptyFileCreator.DESCRIPTOR) + .register(FolderCreator.DESCRIPTOR) + .register(EmptyModelCreator.DESCRIPTOR) + .register(SingleColorTextureFileCreator.DESCRIPTOR) + .register(EmptySceneCreator.DESCRIPTOR); + + LOGGER.info("initialized."); + } + + /** + * Get the available descriptors. + * + * @return the available descriptors. + */ + @FromAnyThread + public @NotNull List getDescriptors() { + return DESCRIPTORS.getExtensions(); + } + + /** + * Create a new creator by the descriptor for the file. + * + * @param descriptor the file creator descriptor. + * @param file the file. + * @return the file creator. + */ + @FromAnyThread + public @Nullable FileCreator newCreator(@NotNull FileCreatorDescriptor descriptor, @NotNull Path file) { + + var constructor = descriptor.getConstructor(); + try { + return constructor.call(); + } catch (Exception e) { + LOGGER.warning(e); + } + + return null; + } + + /** + * Create new creator by the descriptor for the file. + * + * @param descriptor the file creator descriptor. + * @param file the file. + * @return the optional value of file creator. + */ + @FromAnyThread + public @NotNull Optional newCreatorOpt(@NotNull FileCreatorDescriptor descriptor, @NotNull Path file) { + return Optional.ofNullable(newCreator(descriptor, file)); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/AbstractFileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/AbstractFileCreator.java new file mode 100644 index 00000000..0f3e378d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/AbstractFileCreator.java @@ -0,0 +1,433 @@ +package com.ss.builder.fx.component.creator.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.creator.FileCreator; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.fx.util.FXUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.io.IOException; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The base implementation of a file creator. + * + * @author JavaSaBr + */ +public abstract class AbstractFileCreator extends AbstractSimpleEditorDialog implements FileCreator { + + protected static final Logger LOGGER = LoggerManager.getLogger(FileCreator.class); + + protected static final Point DIALOG_SIZE = new Point(900, -1); + + /** + * The resources tree. + */ + @NotNull + private final ResourceTree resourceTree; + + /** + * The preview container. + */ + @Nullable + private final BorderPane previewContainer; + + /** + * The filed with new file name. + */ + @NotNull + private final TextField fileNameField; + + /** + * The init file. + */ + @Nullable + private Path initFile; + + protected AbstractFileCreator() { + this.resourceTree = new ResourceTree(null, true); + this.previewContainer = needPreview()? new BorderPane() : null; + this.fileNameField = new TextField(); + } + + @Override + @FxThread + public void start(@NotNull Path file) { + this.initFile = file; + + show(); + + var currentAsset = EditorConfig.getInstance() + .requiredCurrentAsset(); + + resourceTree.setOnLoadHandler(finished -> expand(file, finished)) + .fill(currentAsset); + + ExecutorManager.getInstance() + .addFxTask(getFileNameField()::requestFocus); + + validateFileName(); + } + + @FxThread + private void expand(@NotNull Path file, @NotNull Boolean finished) { + if (finished) { + resourceTree.expandTo(file, true); + } + } + + /** + * Set the init file. + * + * @param initFile the init file. + */ + @FromAnyThread + private void setInitFile(@NotNull Path initFile) { + this.initFile = initFile; + } + + /** + * Get the init file. + * + * @return the init file. + */ + @FromAnyThread + private @NotNull Path getInitFile() { + return notNull(initFile); + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_CREATE; + } + + /** + * Get the selected file in the resources tree. + * + * @return the selected file in the resources tree. + */ + @FromAnyThread + private @NotNull Path getSelectedFile() { + + var selectedItem = resourceTree.getSelectionModel() + .getSelectedItem(); + + if (selectedItem == null) { + return getInitFile(); + } + + return selectedItem.getValue() + .getFile(); + } + + /** + * Gets file to create. + * + * @return the file to creating. + */ + @FromAnyThread + protected @Nullable Path getFileToCreate() { + + var fileNameField = getFileNameField(); + var filename = fileNameField.getText(); + + if (StringUtils.isEmpty(filename)) { + return null; + } + + var fileExtension = getFileExtension(); + + var selectedFile = getSelectedFile(); + var directory = Files.isDirectory(selectedFile) ? selectedFile : selectedFile.getParent(); + + return StringUtils.isEmpty(fileExtension) ? directory.resolve(filename) : + directory.resolve(filename + "." + fileExtension); + } + + /** + * Get the file extension. + * + * @return the file extension. + */ + @FromAnyThread + protected @NotNull String getFileExtension() { + return StringUtils.EMPTY; + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + + UiUtils.incrementLoading(); + + ExecutorManager.getInstance() + .addBackgroundTask(this::processOkInBackground); + } + + /** + * Handle creating files in background. + */ + @BackgroundThread + private void processOkInBackground() { + + Path tempFile; + try { + tempFile = Files.createTempFile("SSEditor", "fileCreator"); + } catch (final IOException e) { + EditorUtils.handleException(LOGGER, this, e); + UiUtils.decrementLoading(); + return; + } + + Path fileToCreate = notNull(getFileToCreate()); + try { + + writeData(tempFile); + try { + Files.move(tempFile, fileToCreate, REPLACE_EXISTING, ATOMIC_MOVE); + } catch (final AtomicMoveNotSupportedException ex) { + Files.move(tempFile, fileToCreate, REPLACE_EXISTING); + } + + notifyFileCreated(fileToCreate, true); + + } catch (Exception e) { + Utils.run(tempFile, Files::delete); + EditorUtils.handleException(LOGGER, this, e); + } + + UiUtils.decrementLoading(); + } + + /** + * Write created data to the created file. + * + * @param resultFile the result file. + * @throws IOException if was some problem with writing to the result file. + */ + @BackgroundThread + protected void writeData(@NotNull Path resultFile) throws IOException { + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + super.createContent(root); + + var container = new HBox(); + container.prefWidthProperty().bind(widthProperty()); + + var settingsContainer = new GridPane(); + settingsContainer.prefWidthProperty() + .bind(container.widthProperty().multiply(0.5)); + + resourceTree.prefWidthProperty() + .bind(container.widthProperty().multiply(0.5)); + + FxControlUtils.onSelectedItemChange(resourceTree, this::validateFileName); + + createSettings(settingsContainer); + + FxUtils.addChild(container, resourceTree); + + if (needPreview()) { + + var previewContainer = notNull(getPreviewContainer()); + var wrapper = new VBox(); + + settingsContainer.prefHeightProperty() + .bind(container.heightProperty() + .subtract(previewContainer.heightProperty())); + + createPreview(previewContainer); + + FXUtils.bindFixedWidth(previewContainer, wrapper.widthProperty()); + FXUtils.bindFixedHeight(previewContainer, wrapper.widthProperty()); + + FxUtils.addClass(wrapper, CssClasses.DEF_VBOX) + .addClass(previewContainer, CssClasses.DEF_BORDER_PANE); + + FxUtils.addChild(wrapper, settingsContainer, previewContainer) + .addChild(container, wrapper); + + } else { + + settingsContainer.prefHeightProperty() + .bind(container.heightProperty()); + + FxUtils.addChild(container, settingsContainer); + } + + FxUtils.addClass(root, CssClasses.FILE_CREATOR_DIALOG) + .addClass(container, CssClasses.DEF_HBOX) + .addClass(settingsContainer, CssClasses.DEF_GRID_PANE); + + FxUtils.addChild(root, container); + } + + /** + * Notify about the file created. + * + * @param createdFile the created file + * @param needSelect the need select + */ + @FromAnyThread + protected void notifyFileCreated(@NotNull Path createdFile, boolean needSelect) { + + if (!needSelect) { + return; + } + + FxEventManager.getInstance() + .notify(new RequestSelectFileEvent(createdFile)); + } + + /** + * If return true the creator will create {@link #previewContainer}. + * + * @return true if need to create preview container. + */ + @FromAnyThread + protected boolean needPreview() { + return false; + } + + /** + * Get the preview container. + * + * @return the preview container. + */ + @FromAnyThread + protected @Nullable BorderPane getPreviewContainer() { + return previewContainer; + } + + /** + * Create a preview. + * + * @param container the preview container. + */ + @FxThread + protected void createPreview(@NotNull BorderPane container) { + } + + /** + * Get the filed with new file name. + * + * @return the filed with new file name. + */ + @FromAnyThread + protected @NotNull TextField getFileNameField() { + return notNull(fileNameField); + } + + /** + * Create settings of the creating file. + * + * @param root the root + */ + @FxThread + protected void createSettings(@NotNull GridPane root) { + + var fileNameLabel = new Label(getFileNameLabelText() + ":"); + fileNameLabel.prefWidthProperty() + .bind(root.widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); + + fileNameField.prefWidthProperty() + .bind(root.widthProperty()); + + fileNameField.prefWidthProperty() + .bind(root.widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onTextChange(fileNameField, this::validateFileName); + + root.add(fileNameLabel, 0, 0); + root.add(fileNameField, 1, 0); + + FxUtils.addClass(fileNameLabel, + CssClasses.DIALOG_DYNAMIC_LABEL). + addClass(fileNameField, + CssClasses.DIALOG_FIELD); + } + + /** + * Get the file name label text. + * + * @return the label text "file name". + */ + @FromAnyThread + protected @NotNull String getFileNameLabelText() { + return Messages.FILE_CREATOR_FILE_NAME_LABEL; + } + + /** + * Validate the inputted name. + */ + @FxThread + protected void validateFileName() { + + var okButton = getOkButton(); + if (okButton == null) { + return; + } + + var fileToCreate = getFileToCreate(); + + if (fileToCreate == null || Files.exists(fileToCreate)) { + okButton.setDisable(true); + return; + } + + okButton.setDisable(false); + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyFileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyFileCreator.java new file mode 100644 index 00000000..77fefa0a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyFileCreator.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.component.creator.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The creator to create an empty file. + * + * @author JavaSaBr + */ +public class EmptyFileCreator extends AbstractFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.EMPTY_FILE_CREATOR_DESCRIPTION, + EmptyFileCreator::new + ); + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.EMPTY_FILE_CREATOR_TITLE; + } + + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return StringUtils.EMPTY; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyModelCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyModelCreator.java new file mode 100644 index 00000000..12ca670e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptyModelCreator.java @@ -0,0 +1,57 @@ +package com.ss.builder.fx.component.creator.impl; + +import static java.nio.file.StandardOpenOption.*; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.scene.Node; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The creator to create an empty model. + * + * @author JavaSaBr + */ +public class EmptyModelCreator extends AbstractFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.EMPTY_MODEL_CREATOR_DESCRIPTION, + EmptyModelCreator::new + ); + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.EMPTY_MODEL_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.JME_OBJECT; + } + + @Override + @BackgroundThread + protected void writeData(@NotNull Path resultFile) throws IOException { + super.writeData(resultFile); + + var exporter = BinaryExporter.getInstance(); + var newNode = new Node("Model root"); + + try (var out = Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + exporter.save(newNode, out); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/EmptySceneCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptySceneCreator.java new file mode 100644 index 00000000..ca9ab380 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/EmptySceneCreator.java @@ -0,0 +1,81 @@ +package com.ss.builder.fx.component.creator.impl; + +import static java.nio.file.StandardOpenOption.*; +import com.jme3.export.binary.BinaryExporter; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.rlib.common.util.VarTable; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The creator to create an empty scene. + * + * @author JavaSaBr + */ +public class EmptySceneCreator extends GenericFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.EMPTY_SCENE_CREATOR_DESCRIPTION, + EmptySceneCreator::new + ); + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.EMPTY_SCENE_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.JME_SCENE; + } + + @Override + @BackgroundThread + protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { + super.writeData(vars, resultFile); + + var exporter = BinaryExporter.getInstance(); + var newNode = createScene(); + + try (var out = Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + exporter.save(newNode, out); + } + } + + /** + * Create a new scene node. + * + * @return the new scene node + */ + @FxThread + protected @NotNull SceneNode createScene() { + + var newNode = new SceneNode(); + newNode.addLayer(new SceneLayer("Default", true)); + newNode.addLayer(new SceneLayer("TransparentFX", true)); + newNode.addLayer(new SceneLayer("Ignore Raycast", true)); + newNode.addLayer(new SceneLayer("Water", true)); + newNode.getLayers().forEach(SceneLayer::show); + + return newNode; + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/FolderCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/FolderCreator.java new file mode 100644 index 00000000..57eb91ed --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/FolderCreator.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.component.creator.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; + +/** + * The creator to create a folder. + * + * @author JavaSaBr + */ +public class FolderCreator extends AbstractFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.FOLDER_CREATOR_DESCRIPTION, + FolderCreator::new + ); + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.FOLDER_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return StringUtils.EMPTY; + } + + @Override + @FromAnyThread + protected @NotNull String getFileNameLabelText() { + return Messages.FOLDER_CREATOR_FILE_NAME_LABEL; + } + + @Override + @FxThread + protected void processOk() { + super.hide(); + + var fileToCreate = notNull(getFileToCreate()); + try { + Files.createDirectory(fileToCreate); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + notifyFileCreated(fileToCreate, true); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/material/MaterialFileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/material/MaterialFileCreator.java new file mode 100644 index 00000000..52fe3ed2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/material/MaterialFileCreator.java @@ -0,0 +1,136 @@ +package com.ss.builder.fx.component.creator.impl.material; + +import static com.ss.builder.FileExtensions.JME_MATERIAL; +import static java.nio.file.StandardOpenOption.*; +import com.jme3.material.Material; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditablePropertyType; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The creator to create a new material. + * + * @author JavaSaBr + */ +public class MaterialFileCreator extends GenericFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.MATERIAL_FILE_CREATOR_FILE_DESCRIPTION, + MaterialFileCreator::new + ); + + private static final String PBR_MAT_DEF = "Common/MatDefs/Light/PBRLighting.j3md"; + private static final String LIGHTING_MAT_DEF = "Common/MatDefs/Light/Lighting.j3md"; + private static final String PROP_MAT_DEF = "matDef"; + + /** + * The list of available definitions. + */ + @NotNull + private final Array definitions; + + private MaterialFileCreator() { + this.definitions = ResourceManager.getInstance() + .getAvailableResources(FileExtensions.JME_MATERIAL_DEFINITION); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.MATERIAL_FILE_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.JME_MATERIAL; + } + + @Override + @FromAnyThread + protected @NotNull Array getPropertyDefinitions() { + + String def; + + if (definitions.contains(PBR_MAT_DEF)) { + def = PBR_MAT_DEF; + } else if (definitions.contains(LIGHTING_MAT_DEF)) { + def = LIGHTING_MAT_DEF; + } else { + def = definitions.first(); + } + + var type = new PropertyDefinition(EditablePropertyType.STRING_FROM_LIST, + Messages.MATERIAL_FILE_CREATOR_MATERIAL_TYPE_LABEL, PROP_MAT_DEF, def, definitions); + + return Array.of(type); + } + + /** + * Get the list of available definitions. + * + * @return the list of available definitions. + */ + @FromAnyThread + private @NotNull Array getDefinitions() { + return definitions; + } + + @Override + @FxThread + protected boolean validate(@NotNull VarTable vars) { + + var matDef = vars.get(PROP_MAT_DEF, String.class, StringUtils.EMPTY); + + if (matDef.isEmpty() || !getDefinitions().contains(matDef)) { + return false; + } + + return super.validate(vars); + } + + @Override + @BackgroundThread + protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { + super.writeData(vars, resultFile); + + var assetManager = EditorUtils.getAssetManager(); + var matDef = vars.get(PROP_MAT_DEF, String.class); + + var material = new Material(assetManager, matDef); + material.getAdditionalRenderState(); + + var materialContent = MaterialSerializer.serializeToString(material); + + try (var out = new PrintWriter(Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE))) { + out.print(materialContent); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java new file mode 100644 index 00000000..623da7f6 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java @@ -0,0 +1,167 @@ +package com.ss.builder.fx.component.creator.impl.material.definition; + +import static com.ss.builder.FileExtensions.JME_MATERIAL_DEFINITION; +import static com.ss.editor.extension.property.EditablePropertyType.STRING_FROM_LIST; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.lang.Character.toUpperCase; +import static java.nio.file.StandardOpenOption.*; +import com.jme3.material.TechniqueDef.LightMode; +import com.jme3.renderer.Caps; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayCollectors; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; + +/** + * The creator to create a new material definition. + * + * @author JavaSaBr + */ +public class MaterialDefinitionFileCreator extends GenericFileCreator { + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.MATERIAL_DEFINITION_FILE_CREATOR_FILE_DESCRIPTION, + MaterialDefinitionFileCreator::new + ); + + private static final String PROP_GLSL_VERSION = "glslVersion"; + private static final String MD_TEMPLATE; + private static final String FRAG_TEMPLATE; + private static final String VERT_TEMPLATE; + + static { + MD_TEMPLATE = FileUtils.readFromClasspath("/template/matdef/empty.j3md"); + FRAG_TEMPLATE = FileUtils.readFromClasspath("/template/frag/empty.frag"); + VERT_TEMPLATE = FileUtils.readFromClasspath("/template/vert/empty.vert"); + } + + /** + * The list of available GLSL versions. + */ + @NotNull + private final Array availableGlsl; + + private MaterialDefinitionFileCreator() { + this.availableGlsl = EditorUtils.getRenderer() + .getCaps() + .stream() + .filter(cap -> cap.name().startsWith("GLSL")) + .map(Enum::name) + .sorted(StringUtils::compareIgnoreCase) + .collect(ArrayCollectors.toArray(String.class)); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.MATERIAL_DEFINITION_FILE_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.JME_MATERIAL_DEFINITION; + } + + @Override + @FxThread + protected boolean validate(@NotNull VarTable vars) { + + var glslVersion = vars.get(PROP_GLSL_VERSION, String.class, StringUtils.EMPTY); + + if (glslVersion.isEmpty() || !availableGlsl.contains(glslVersion)) { + return false; + } + + return super.validate(vars); + } + + @Override + @FromAnyThread + protected @NotNull Array getPropertyDefinitions() { + + var result = Array.ofType(PropertyDefinition.class); + result.add(new PropertyDefinition(STRING_FROM_LIST, Messages.MATERIAL_DEFINITION_FILE_CREATOR_GLSL_LABEL, + PROP_GLSL_VERSION, Caps.GLSL150.name(), availableGlsl)); + + return result; + } + + @Override + @FxThread + protected void processOk() { + super.hide(); + + var matDefFile = notNull(getFileToCreate()); + var filename = FileUtils.getNameWithoutExtension(matDefFile); + + var parent = matDefFile.getParent(); + var fragmentFile = parent.resolve(filename + "." + FileExtensions.GLSL_FRAGMENT); + var vertexFile = parent.resolve(filename + "." + FileExtensions.GLSL_VERTEX); + + var editorConfig = EditorConfig.getInstance(); + var assetFolder = notNull(editorConfig.getCurrentAsset()); + + var pathToFragment = assetFolder.relativize(fragmentFile); + var pathToVertex = assetFolder.relativize(vertexFile); + + var glslVersion = vars.getString(PROP_GLSL_VERSION); + + var mdName = filename.length() > 1 ? + toUpperCase(filename.charAt(0)) + filename.substring(1, filename.length()) : filename; + + var mdContent = MD_TEMPLATE.replace("${matdef-name}", mdName); + mdContent = mdContent.replace("${light-mode}", LightMode.SinglePass.name()); + mdContent = mdContent.replace("${GLSL-version}", glslVersion); + mdContent = mdContent.replace("${vertex-path}", pathToVertex.toString()); + mdContent = mdContent.replace("${fragment-path}", pathToFragment.toString()); + + try (var out = new PrintWriter(Files.newOutputStream(matDefFile, WRITE, TRUNCATE_EXISTING, CREATE))) { + out.print(mdContent); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + try (var out = new PrintWriter(Files.newOutputStream(fragmentFile, WRITE, TRUNCATE_EXISTING, CREATE))) { + out.print(FRAG_TEMPLATE); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + try (var out = new PrintWriter(Files.newOutputStream(vertexFile, WRITE, TRUNCATE_EXISTING, CREATE))) { + out.print(VERT_TEMPLATE); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + notifyFileCreated(matDefFile, true); + notifyFileCreated(fragmentFile, false); + notifyFileCreated(vertexFile, false); + } +} diff --git a/src/main/java/com/ss/builder/fx/component/creator/impl/texture/SingleColorTextureFileCreator.java b/src/main/java/com/ss/builder/fx/component/creator/impl/texture/SingleColorTextureFileCreator.java new file mode 100644 index 00000000..da269f47 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/creator/impl/texture/SingleColorTextureFileCreator.java @@ -0,0 +1,161 @@ +package com.ss.builder.fx.component.creator.impl.texture; + +import static com.ss.editor.extension.property.EditablePropertyType.COLOR; +import static com.ss.editor.extension.property.EditablePropertyType.INTEGER; +import com.jme3.math.ColorRGBA; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.embed.swing.SwingFXUtils; +import javafx.scene.image.ImageView; +import javafx.scene.image.WritableImage; +import javafx.scene.layout.BorderPane; +import org.jetbrains.annotations.NotNull; + +import javax.imageio.ImageIO; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The creator to create a texture which filled one color. + * + * @author JavaSaBr + */ +public class SingleColorTextureFileCreator extends GenericFileCreator { + + private static final String PROP_COLOR = "color"; + private static final String PROP_HEIGHT = "height"; + private static final String PROP_WIDTH = "width"; + + public static final FileCreatorDescriptor DESCRIPTOR = new FileCreatorDescriptor( + Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_DESCRIPTION, + SingleColorTextureFileCreator::new + ); + + @NotNull + private static final Array DEFINITIONS = ArrayFactory.newArray(PropertyDefinition.class); + + static { + DEFINITIONS.add(new PropertyDefinition(COLOR, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_COLOR, PROP_COLOR, ColorRGBA.Gray)); + DEFINITIONS.add(new PropertyDefinition(INTEGER, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_HEIGHT, PROP_HEIGHT, 2, 1, 256)); + DEFINITIONS.add(new PropertyDefinition(INTEGER, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_WIDTH, PROP_WIDTH, 2, 1, 256)); + } + + /** + * The image view to show preview of texture. + */ + @NotNull + private final ImageView imageView; + + private SingleColorTextureFileCreator() { + this.imageView = new ImageView(); + } + + @Override + @FxThread + protected void createPreview(@NotNull BorderPane container) { + super.createPreview(container); + container.setCenter(imageView); + } + + /** + * Get the image view to show preview of texture. + * + * @return the image view to show preview of texture. + */ + @FxThread + private @NotNull ImageView getImageView() { + return imageView; + } + + @Override + @FromAnyThread + protected boolean needPreview() { + return true; + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.IMAGE_PNG; + } + + @Override + @FromAnyThread + protected @NotNull Array getPropertyDefinitions() { + return DEFINITIONS; + } + + @Override + @FxThread + protected boolean validate(@NotNull VarTable vars) { + + var color = UiUtils.from(vars.get(PROP_COLOR, ColorRGBA.class)); + + var width = vars.getInteger(PROP_WIDTH); + var height = vars.getInteger(PROP_HEIGHT); + + var writableImage = new WritableImage(width, height); + var pixelWriter = writableImage.getPixelWriter(); + + for (var i = 0; i < width; i++) { + for (var j = 0; j < height; j++) { + pixelWriter.setColor(i, j, color); + } + } + + getImageView().setImage(writableImage); + + return true; + } + + @Override + @BackgroundThread + protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { + super.writeData(vars, resultFile); + + var color = UiUtils.from(vars.get(PROP_COLOR, ColorRGBA.class)); + + var width = vars.getInteger(PROP_WIDTH); + var height = vars.getInteger(PROP_HEIGHT); + + var writableImage = new WritableImage(width, height); + var pixelWriter = writableImage.getPixelWriter(); + + for (var i = 0; i < width; i++) { + for (var j = 0; j < height; j++) { + pixelWriter.setColor(i, j, color); + } + } + + var bufferedImage = SwingFXUtils.fromFXImage(writableImage, null); + + try (var out = Files.newOutputStream(resultFile)) { + ImageIO.write(bufferedImage, "png", out); + } + } +} diff --git a/src/main/java/com/ss/editor/ui/component/log/LogView.java b/src/main/java/com/ss/builder/fx/component/log/LogView.java similarity index 94% rename from src/main/java/com/ss/editor/ui/component/log/LogView.java rename to src/main/java/com/ss/builder/fx/component/log/LogView.java index 41eb78a6..d38620dd 100644 --- a/src/main/java/com/ss/editor/ui/component/log/LogView.java +++ b/src/main/java/com/ss/builder/fx/component/log/LogView.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.component.log; +package com.ss.builder.fx.component.log; import static java.util.Collections.singleton; import com.jme3.material.Material; @@ -6,9 +6,12 @@ import com.jme3.texture.Texture2D; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.image.ColorSpace; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.css.CssIds; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssIds; import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.model.StyleSpans; import org.fxmisc.richtext.model.StyleSpansBuilder; @@ -27,7 +30,6 @@ */ public class LogView extends CodeArea { - @NotNull private static final LogView INSTANCE = new LogView(); private static final int MAX_LENGTH = 8000; @@ -36,7 +38,6 @@ public class LogView extends CodeArea { return INSTANCE; } - @NotNull private static final String[] FRAMEWORKS = { "log4j", "java.lang.", @@ -49,7 +50,6 @@ public class LogView extends CodeArea { "com.ss.editor.model.", }; - @NotNull private static final String[] CLASSES = { BufferOverflowException.class.getName(), NullPointerException.class.getName(), @@ -72,16 +72,10 @@ public class LogView extends CodeArea { "WARN", "INFO", "ERROR", "DEBUG", "WARNING" }; - @NotNull private static final String SEVERITY_PATTERN = "\\b(" + String.join("|", SEVERITIES) + ")\\b"; - - @NotNull private static final String FRAMEWORK_PATTERN = "\\b(" + String.join("|", FRAMEWORKS) + ")\\b"; - - @NotNull private static final String CLASS_PATTERN = "\\b(" + String.join("|", CLASSES) + ")\\b"; - @NotNull private static final Pattern PATTERN = Pattern.compile( "(?" + SEVERITY_PATTERN + ")" + "|(?" + FRAMEWORK_PATTERN + ")" diff --git a/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java b/src/main/java/com/ss/builder/fx/component/log/OutputStreamWrapper.java similarity index 94% rename from src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java rename to src/main/java/com/ss/builder/fx/component/log/OutputStreamWrapper.java index bac44953..194ab58c 100644 --- a/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java +++ b/src/main/java/com/ss/builder/fx/component/log/OutputStreamWrapper.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.component.log; +package com.ss.builder.fx.component.log; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/component/painting/ComponentConstructor.java b/src/main/java/com/ss/builder/fx/component/painting/ComponentConstructor.java new file mode 100644 index 00000000..ed141123 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/painting/ComponentConstructor.java @@ -0,0 +1,23 @@ +package com.ss.builder.fx.component.painting; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to create a painting component. + * + * @author JavaSaBr + */ +@FunctionalInterface +public interface ComponentConstructor { + + /** + * Create a new painting component. + * + * @param container the container. + * @return the new painting component. + */ + @FxThread + @NotNull PaintingComponent create(@NotNull PaintingComponentContainer container); +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponent.java b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponent.java similarity index 92% rename from src/main/java/com/ss/editor/ui/component/painting/PaintingComponent.java rename to src/main/java/com/ss/builder/fx/component/painting/PaintingComponent.java index 101f3b3c..58a4a0fd 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponent.java +++ b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponent.java @@ -1,8 +1,8 @@ -package com.ss.editor.ui.component.painting; +package com.ss.builder.fx.component.painting; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.EditorState; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.state.EditorState; import com.ss.rlib.common.util.HasName; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentContainer.java b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentContainer.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/painting/PaintingComponentContainer.java rename to src/main/java/com/ss/builder/fx/component/painting/PaintingComponentContainer.java index 6731be73..7e98332d 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentContainer.java +++ b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentContainer.java @@ -1,14 +1,22 @@ -package com.ss.editor.ui.component.painting; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.editor.Editor3DProvider; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; +package com.ss.builder.fx.component.painting; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.editor.Editor3DProvider; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.editor.Editor3DProvider; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.fx.util.FxUtils; import javafx.beans.value.ObservableValue; diff --git a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentListCell.java b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentListCell.java similarity index 89% rename from src/main/java/com/ss/editor/ui/component/painting/PaintingComponentListCell.java rename to src/main/java/com/ss/builder/fx/component/painting/PaintingComponentListCell.java index d5b06d5d..50854fa1 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentListCell.java +++ b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentListCell.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.component.painting; +package com.ss.builder.fx.component.painting; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.StringUtils; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; diff --git a/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentRegistry.java b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentRegistry.java new file mode 100644 index 00000000..5139de15 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/painting/PaintingComponentRegistry.java @@ -0,0 +1,65 @@ +package com.ss.builder.fx.component.painting; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.painting.spawn.SpawnPaintingComponent; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.painting.spawn.SpawnPaintingComponent; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayCollectors; +import org.jetbrains.annotations.NotNull; + +/** + * The registry of all painting components. + * + * @author JavaSaBr + */ +public class PaintingComponentRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(PaintingComponentRegistry.class); + + /** + * @see ComponentConstructor + */ + public static final String EP_CONSTRUCTORS = "PaintingComponentRegistry#constructors"; + + private static final ExtensionPoint CONSTRUCTORS = + ExtensionPointManager.register(EP_CONSTRUCTORS); + + private static final PaintingComponentRegistry INSTANCE = new PaintingComponentRegistry(); + + @FromAnyThread + public static @NotNull PaintingComponentRegistry getInstance() { + return INSTANCE; + } + + private PaintingComponentRegistry() { + + CONSTRUCTORS.register(TerrainPaintingComponent::new) + .register(SpawnPaintingComponent::new); + + LOGGER.info("initialized."); + } + + + /** + * Create all available painting components. + * + * @param container painting component's container. + * @return all available painting components. + */ + @FxThread + public @NotNull Array createComponents(@NotNull PaintingComponentContainer container) { + return CONSTRUCTORS.getExtensions() + .stream() + .map(constructor -> constructor.create(container)) + .collect(ArrayCollectors.toArray(PaintingComponent.class)); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java b/src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingComponent.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java rename to src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingComponent.java index 47ec823f..50f1c408 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java +++ b/src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingComponent.java @@ -1,17 +1,17 @@ -package com.ss.editor.ui.component.painting.impl; +package com.ss.builder.fx.component.painting.impl; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingControl; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.ui.component.painting.PaintingComponent; -import com.ss.editor.ui.component.painting.PaintingComponentContainer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.editor.state.EditorState; +import com.ss.builder.fx.component.painting.PaintingComponent; +import com.ss.builder.fx.component.painting.PaintingComponentContainer; +import com.ss.builder.jme.control.painting.PaintingControl; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import javafx.scene.layout.VBox; diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java b/src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingStateWithEditorTool.java similarity index 84% rename from src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java rename to src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingStateWithEditorTool.java index f9102328..7eee826f 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java +++ b/src/main/java/com/ss/builder/fx/component/painting/impl/AbstractPaintingStateWithEditorTool.java @@ -1,10 +1,10 @@ -package com.ss.editor.ui.component.painting.impl; +package com.ss.builder.fx.component.painting.impl; import static java.lang.Math.abs; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.impl.AbstractEditorState; -import com.ss.editor.ui.component.editor.state.impl.AdditionalEditorState; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.state.impl.AbstractEditorState; +import com.ss.builder.editor.state.impl.AdditionalEditorState; /** * The state of painting component. diff --git a/src/main/java/com/ss/builder/fx/component/painting/impl/PaintingBrushType.java b/src/main/java/com/ss/builder/fx/component/painting/impl/PaintingBrushType.java new file mode 100644 index 00000000..13fa1a4c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/painting/impl/PaintingBrushType.java @@ -0,0 +1,13 @@ +package com.ss.builder.fx.component.painting.impl; + +/** + * The enum of brush types. + * + * @author JavaSaBr + */ +public enum PaintingBrushType { + /** + * Sphere brush type. + */ + SPHERE, +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java b/src/main/java/com/ss/builder/fx/component/painting/property/PaintingPropertyDefinition.java similarity index 82% rename from src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java rename to src/main/java/com/ss/builder/fx/component/painting/property/PaintingPropertyDefinition.java index c00dbe9a..1c55ce8c 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java +++ b/src/main/java/com/ss/builder/fx/component/painting/property/PaintingPropertyDefinition.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.component.painting.property; +package com.ss.builder.fx.component.painting.property; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.EditablePropertyType; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.PropertyDefinition; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java b/src/main/java/com/ss/builder/fx/component/painting/property/PropertiesBasedPaintingComponent.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java rename to src/main/java/com/ss/builder/fx/component/painting/property/PropertiesBasedPaintingComponent.java index db8207ae..d06f934b 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java +++ b/src/main/java/com/ss/builder/fx/component/painting/property/PropertiesBasedPaintingComponent.java @@ -1,16 +1,16 @@ -package com.ss.editor.ui.component.painting.property; +package com.ss.builder.fx.component.painting.property; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingControl; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.plugin.api.property.control.PropertyEditorControl; -import com.ss.editor.plugin.api.property.control.PropertyEditorControlFactory; -import com.ss.editor.ui.component.painting.PaintingComponentContainer; -import com.ss.editor.ui.component.painting.impl.AbstractPaintingComponent; -import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.fx.component.painting.PaintingComponentContainer; +import com.ss.builder.fx.component.painting.impl.AbstractPaintingComponent; +import com.ss.builder.fx.component.painting.impl.AbstractPaintingStateWithEditorTool; +import com.ss.builder.jme.control.painting.PaintingControl; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java b/src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingComponent.java similarity index 78% rename from src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java rename to src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingComponent.java index 163d1f9b..527eb017 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java +++ b/src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingComponent.java @@ -1,22 +1,32 @@ -package com.ss.editor.ui.component.painting.spawn; +package com.ss.builder.fx.component.painting.spawn; import static com.ss.editor.extension.property.EditablePropertyType.*; import com.jme3.asset.AssetNotFoundException; import com.jme3.math.Vector3f; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.spawn.SpawnToolControl; -import com.ss.editor.control.painting.spawn.SpawnToolControl.SpawnMethod; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.painting.PaintingComponentContainer; -import com.ss.editor.ui.component.painting.property.PaintingPropertyDefinition; -import com.ss.editor.ui.component.painting.property.PropertiesBasedPaintingComponent; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.spawn.SpawnToolControl; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.painting.property.PaintingPropertyDefinition; +import com.ss.builder.fx.component.painting.property.PropertiesBasedPaintingComponent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.spawn.SpawnToolControl; +import com.ss.builder.jme.control.painting.spawn.SpawnToolControl.SpawnMethod; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.painting.PaintingComponentContainer; +import com.ss.builder.fx.component.painting.property.PaintingPropertyDefinition; +import com.ss.builder.fx.component.painting.property.PropertiesBasedPaintingComponent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -34,7 +44,7 @@ public class SpawnPaintingComponent extends PropertiesBasedPaintingComponent { - private static final SpawnMethod[] SPAWN_METHODS = SpawnMethod.values(); + private static final SpawnToolControl.SpawnMethod[] SPAWN_METHODS = SpawnToolControl.SpawnMethod.values(); private static final String CATEGORY_DEFAULT = "Default"; @@ -58,7 +68,7 @@ public SpawnPaintingComponent(@NotNull PaintingComponentContainer container) { var result = ArrayFactory.newArray(PaintingPropertyDefinition.class); result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, ENUM, - Messages.MODEL_PROPERTY_METHOD, PROPERTY_METHOD, SpawnMethod.BATCH)); + Messages.MODEL_PROPERTY_METHOD, PROPERTY_METHOD, SpawnToolControl.SpawnMethod.BATCH)); result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, VECTOR_3F, Messages.MODEL_PROPERTY_MIN_SCALE, PROPERTY_MIN_SCALE, new Vector3f(1F, 1F, 1F))); result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, VECTOR_3F, @@ -99,7 +109,7 @@ protected void syncValues(@NotNull VarTable vars, @NotNull SpawnPaintingStateWit .getName(); } - var method = vars.getEnum(PROPERTY_METHOD, SpawnMethod.class); + var method = vars.getEnum(PROPERTY_METHOD, SpawnToolControl.SpawnMethod.class); var minScale = vars.get(PROPERTY_MIN_SCALE, Vector3f.class); var maxScale = vars.get(PROPERTY_MAX_SCALE, Vector3f.class); var padding = vars.get(PROPERTY_PADDING, Vector3f.class); @@ -120,7 +130,7 @@ protected void syncValues(@NotNull VarTable vars, @NotNull SpawnPaintingStateWit @JmeThread protected void syncValues(@NotNull SpawnPaintingStateWithEditorTool state, @NotNull SpawnToolControl toolControl) { super.syncValues(state, toolControl); - toolControl.setMethod(SpawnMethod.valueOf(state.getMethod())); + toolControl.setMethod(SpawnToolControl.SpawnMethod.valueOf(state.getMethod())); toolControl.setMinScale(state.getMinScale()); toolControl.setMaxScale(state.getMaxScale()); toolControl.setPadding(state.getPadding()); @@ -138,7 +148,7 @@ protected void readState(@NotNull SpawnPaintingStateWithEditorTool state, @NotNu vars.set(PROPERTY_MAX_SCALE, state.getMaxScale()); vars.set(PROPERTY_PADDING, state.getPadding()); - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); for (int i = 1; i <= AVAILABLE_MODELS; i++) { diff --git a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java b/src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingStateWithEditorTool.java similarity index 89% rename from src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java rename to src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingStateWithEditorTool.java index 1bf5340f..03e461de 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java +++ b/src/main/java/com/ss/builder/fx/component/painting/spawn/SpawnPaintingStateWithEditorTool.java @@ -1,9 +1,11 @@ -package com.ss.editor.ui.component.painting.spawn; +package com.ss.builder.fx.component.painting.spawn; import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.control.painting.spawn.SpawnToolControl.SpawnMethod; -import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.control.painting.spawn.SpawnToolControl; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.control.painting.spawn.SpawnToolControl.SpawnMethod; +import com.ss.builder.fx.component.painting.impl.AbstractPaintingStateWithEditorTool; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -50,7 +52,7 @@ public class SpawnPaintingStateWithEditorTool extends AbstractPaintingStateWithE private int method; public SpawnPaintingStateWithEditorTool() { - this.method = SpawnMethod.BATCH.ordinal(); + this.method = SpawnToolControl.SpawnMethod.BATCH.ordinal(); this.selectedModels = new String[SpawnPaintingComponent.AVAILABLE_MODELS]; this.minScale = Vector3f.UNIT_XYZ.clone(); this.maxScale = Vector3f.UNIT_XYZ.clone(); diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java b/src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingComponent.java similarity index 93% rename from src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java rename to src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingComponent.java index ba6d7057..283bd064 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java +++ b/src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingComponent.java @@ -1,29 +1,42 @@ -package com.ss.editor.ui.component.painting.terrain; +package com.ss.builder.fx.component.painting.terrain; import static com.ss.editor.extension.property.EditablePropertyType.BOOLEAN; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; -import static com.ss.editor.ui.component.painting.PaintingComponentContainer.FIELD_PERCENT; -import static com.ss.editor.ui.component.painting.PaintingComponentContainer.LABEL_PERCENT; +import static com.ss.builder.fx.component.painting.PaintingComponentContainer.FIELD_PERCENT; +import static com.ss.builder.fx.component.painting.PaintingComponentContainer.LABEL_PERCENT; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.array.ArrayFactory.toArray; import com.jme3.scene.Node; import com.jme3.terrain.Terrain; import com.jme3.terrain.geomipmap.TerrainQuad; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.terrain.*; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.painting.PaintingComponentContainer; -import com.ss.editor.ui.component.painting.property.PaintingPropertyDefinition; -import com.ss.editor.ui.component.painting.property.PropertiesBasedPaintingComponent; -import com.ss.editor.ui.component.painting.terrain.paint.TextureLayerSettings; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.MaterialUtils; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.terrain.*; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.painting.property.PaintingPropertyDefinition; +import com.ss.builder.fx.component.painting.property.PropertiesBasedPaintingComponent; +import com.ss.builder.fx.component.painting.terrain.paint.TextureLayerSettings; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.MaterialUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.terrain.*; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.painting.PaintingComponentContainer; +import com.ss.builder.fx.component.painting.property.PaintingPropertyDefinition; +import com.ss.builder.fx.component.painting.property.PropertiesBasedPaintingComponent; +import com.ss.builder.fx.component.painting.terrain.paint.TextureLayerSettings; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.MaterialUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; @@ -555,7 +568,7 @@ private void createPaintControlSettings() { shininessLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); shininessField = new FloatTextField(); - shininessField.setMinMax(0F, Integer.MAX_VALUE); + shininessField.setMinMax(0F, (float) Integer.MAX_VALUE); shininessField.prefWidthProperty() .bind(widthProperty().multiply(FIELD_PERCENT)); diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java b/src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingStateWithEditorTool.java similarity index 95% rename from src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java rename to src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingStateWithEditorTool.java index 954310ca..5b795584 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java +++ b/src/main/java/com/ss/builder/fx/component/painting/terrain/TerrainPaintingStateWithEditorTool.java @@ -1,8 +1,9 @@ -package com.ss.editor.ui.component.painting.terrain; +package com.ss.builder.fx.component.painting.terrain; import static java.lang.Math.abs; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.painting.impl.AbstractPaintingStateWithEditorTool; /** * The state of terrain painting component. diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayer.java b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayer.java similarity index 77% rename from src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayer.java rename to src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayer.java index 5905c2f4..efcf1305 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayer.java +++ b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayer.java @@ -1,11 +1,13 @@ -package com.ss.editor.ui.component.painting.terrain.paint; +package com.ss.builder.fx.component.painting.terrain.paint; -import static com.ss.editor.util.EditorUtil.*; +import static com.ss.builder.util.EditorUtils.*; import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; import com.jme3.texture.Texture; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.EditorUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -96,7 +98,7 @@ public void setScale(final float scale) { return null; } - return getRealFile(assetKey.getName()); + return EditorUtils.getRealFile(assetKey.getName()); } /** @@ -106,9 +108,9 @@ public void setScale(final float scale) { */ @FromAnyThread public void setDiffuseFile(@Nullable final Path diffuseFile) { - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Path assetFile = diffuseFile == null ? null : getAssetFile(diffuseFile); - final String assetPath = assetFile == null ? null : toAssetPath(assetFile); + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Path assetFile = diffuseFile == null ? null : EditorUtils.getAssetFile(diffuseFile); + final String assetPath = assetFile == null ? null : EditorUtils.toAssetPath(assetFile); final Texture texture = assetPath == null ? null : assetManager.loadTexture(assetPath); settings.setDiffuse(texture, getLayer()); } @@ -127,7 +129,7 @@ public void setDiffuseFile(@Nullable final Path diffuseFile) { return null; } - return getRealFile(assetKey.getName()); + return EditorUtils.getRealFile(assetKey.getName()); } /** @@ -137,9 +139,9 @@ public void setDiffuseFile(@Nullable final Path diffuseFile) { */ @FromAnyThread public void setNormalFile(@Nullable final Path normalFile) { - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Path assetFile = normalFile == null ? null : getAssetFile(normalFile); - final String assetPath = assetFile == null ? null : toAssetPath(assetFile); + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Path assetFile = normalFile == null ? null : EditorUtils.getAssetFile(normalFile); + final String assetPath = assetFile == null ? null : EditorUtils.toAssetPath(assetFile); final Texture texture = assetPath == null ? null : assetManager.loadTexture(assetPath); settings.setNormal(texture, getLayer()); } diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerCell.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java rename to src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerCell.java index 1e371a44..56e6ff5a 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java +++ b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerCell.java @@ -1,11 +1,13 @@ -package com.ss.editor.ui.component.painting.terrain.paint; - -import static com.ss.editor.ui.component.painting.PaintingComponentContainer.FIELD_PERCENT; -import static com.ss.editor.ui.component.painting.PaintingComponentContainer.LABEL_PERCENT; -import com.ss.editor.Messages; -import com.ss.editor.ui.control.choose.NamedChooseTextureControl; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; +package com.ss.builder.fx.component.painting.terrain.paint; + +import static com.ss.builder.fx.component.painting.PaintingComponentContainer.FIELD_PERCENT; +import static com.ss.builder.fx.component.painting.PaintingComponentContainer.LABEL_PERCENT; +import com.ss.builder.Messages; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.fx.control.choose.NamedChooseTextureControl; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.control.input.FloatTextField; import com.ss.rlib.fx.util.FXUtils; import javafx.beans.binding.DoubleBinding; @@ -85,7 +87,7 @@ public TextureLayerCell(final DoubleBinding prefWidth, scaleLabel.prefWidthProperty().bind(settingContainer.widthProperty().multiply(LABEL_PERCENT)); scaleField = new FloatTextField(); - scaleField.setMinMax(0.0001F, Integer.MAX_VALUE); + scaleField.setMinMax(0.0001F, (float) Integer.MAX_VALUE); scaleField.setScrollPower(3F); scaleField.addChangeListener((observable, oldValue, newValue) -> updateScale(newValue)); scaleField.prefWidthProperty().bind(settingContainer.widthProperty().multiply(FIELD_PERCENT)); diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerSettings.java b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerSettings.java similarity index 93% rename from src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerSettings.java rename to src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerSettings.java index 893a34c2..56e43283 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerSettings.java +++ b/src/main/java/com/ss/builder/fx/component/painting/terrain/paint/TextureLayerSettings.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui.component.painting.terrain.paint; +package com.ss.builder.fx.component.painting.terrain.paint; -import static com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent.TERRAIN_PARAM; +import static com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent.TERRAIN_PARAM; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.material.MatParam; import com.jme3.material.Material; @@ -8,19 +8,30 @@ import com.jme3.scene.Node; import com.jme3.terrain.Terrain; import com.jme3.texture.Texture; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.terrain.PaintTerrainToolControl; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.terrain.PaintTerrainToolControl; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.terrain.PaintTerrainToolControl; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/builder/fx/component/scripting/EditorScriptingComponent.java b/src/main/java/com/ss/builder/fx/component/scripting/EditorScriptingComponent.java new file mode 100644 index 00000000..478f1153 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/scripting/EditorScriptingComponent.java @@ -0,0 +1,212 @@ +package com.ss.builder.fx.component.scripting; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import com.ss.rlib.fx.util.FxUtils; +import groovy.lang.GroovyShell; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; +import org.jetbrains.annotations.NotNull; + +/** + * The component to work with scripts in an editor. + * + * @author JavaSaBr + */ +public class EditorScriptingComponent extends GridPane { + + /** + * The table of variables. + */ + @NotNull + private final ObjectDictionary variables; + + /** + * The table of variable to type. + */ + @NotNull + private final ObjectDictionary> variableToType; + + /** + * The list of imports. + */ + @NotNull + private final Array imports; + + /** + * The shell. + */ + @NotNull + private final GroovyShell shell; + + /** + * The header component. + */ + @NotNull + private final GroovyEditorComponent headerComponent; + + /** + * The editor component. + */ + @NotNull + private final GroovyEditorComponent editorComponent; + + /** + * The apply handler. + */ + @NotNull + private final Runnable applyHandler; + + public EditorScriptingComponent(@NotNull Runnable applyHandler) { + this.applyHandler = applyHandler; + + this.editorComponent = new GroovyEditorComponent(true); + this.editorComponent.setFocusTraversable(true); + this.editorComponent.prefHeightProperty().bind(heightProperty().multiply(0.6)); + this.editorComponent.prefWidthProperty().bind(widthProperty()); + this.headerComponent = new GroovyEditorComponent(false); + this.headerComponent.prefHeightProperty().bind(heightProperty().multiply(0.4)); + this.headerComponent.prefWidthProperty().bind(widthProperty()); + this.shell = new GroovyShell(); + this.variables = ObjectDictionary.ofType(String.class, Object.class); + this.variableToType = ObjectDictionary.ofType(String.class, Class.class); + this.imports = ArrayFactory.newArray(String.class); + + var headersLabel = new Label(Messages.EDITOR_SCRIPTING_COMPONENT_HEADERS + ":"); + var scriptBodyLabel = new Label(Messages.EDITOR_SCRIPTING_COMPONENT_BODY + ":"); + + var runButton = new Button(Messages.EDITOR_SCRIPTING_COMPONENT_RUN); + runButton.setOnAction(event -> run()); + + add(headersLabel, 0, 0, 1, 1); + add(headerComponent, 0, 1, 1, 1); + add(scriptBodyLabel, 0, 2, 1, 1); + add(editorComponent, 0, 3, 1, 1); + add(runButton, 0, 4, 1, 1); + + FxUtils.addClass(this, CssClasses.EDITOR_SCRIPTING_COMPONENT); + } + + /** + * Add a global variable to the script. + * + * @param name the name of the variable. + * @param value the variable. + */ + @FromAnyThread + public void addVariable(@NotNull String name, @NotNull Object value) { + variables.put(name, value); + addImport(value.getClass()); + } + + /** + * Add a global variable to the script. + * + * @param name the name of the variable. + * @param value the variable. + * @param type the expected type of the variable. + */ + @FromAnyThread + public void addVariable(@NotNull String name, @NotNull T value, @NotNull Class type) { + variables.put(name, value); + variableToType.put(name, type); + addImport(type.getClass()); + } + + + /** + * Add an import of a some type. + * + * @param type the type. + */ + @FromAnyThread + public void addImport(@NotNull Class type) { + + var name = type.getName(); + + if (!imports.contains(name)) { + imports.add(name); + } + } + + /** + * Build a header of a script. + */ + @FromAnyThread + public void buildHeader() { + + var result = new StringBuilder(); + + imports.forEach(result, (type, builder) -> builder.append("import ") + .append(type) + .append('\n')); + + result.append('\n'); + + variables.forEach((name, value) -> { + + Class type = variableToType.get(name); + + if (type == null) { + type = value.getClass(); + } + + result.append(type.getSimpleName()) + .append(' ') + .append(name) + .append(" = load_") + .append(name) + .append("();\n"); + }); + + headerComponent.setCode(result.toString()); + } + + /** + * Set an example of groovy code. + * + * @param example the example code. + */ + public void setExampleCode(@NotNull String example) { + editorComponent.setCode(example); + } + + /** + * Run the current script. + */ + private void run() { + + String code = editorComponent.getCode(); + + for (var type : imports) { + var check = "import " + type; + if (code.contains(check)) { + code = code.replace(check, ""); + } + } + + var result = new StringBuilder(); + + imports.forEach(result, (type, builder) -> builder.append("import ") + .append(type) + .append('\n')); + + result.append(code); + + variables.forEach(shell, GroovyShell::setVariable); + try { + shell.evaluate(result.toString()); + } catch (Exception e) { + EditorUtils.handleException(null, this, e); + return; + } + + applyHandler.run(); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/scripting/GroovyEditorComponent.java b/src/main/java/com/ss/builder/fx/component/scripting/GroovyEditorComponent.java similarity index 96% rename from src/main/java/com/ss/editor/ui/component/scripting/GroovyEditorComponent.java rename to src/main/java/com/ss/builder/fx/component/scripting/GroovyEditorComponent.java index 454058d8..ae1be3d3 100644 --- a/src/main/java/com/ss/editor/ui/component/scripting/GroovyEditorComponent.java +++ b/src/main/java/com/ss/builder/fx/component/scripting/GroovyEditorComponent.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.component.scripting; +package com.ss.builder.fx.component.scripting; import static java.util.Collections.singleton; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.layout.VBox; import org.fxmisc.richtext.CodeArea; diff --git a/src/main/java/com/ss/editor/ui/component/split/pane/EditorToolSplitPane.java b/src/main/java/com/ss/builder/fx/component/split/pane/EditorToolSplitPane.java similarity index 89% rename from src/main/java/com/ss/editor/ui/component/split/pane/EditorToolSplitPane.java rename to src/main/java/com/ss/builder/fx/component/split/pane/EditorToolSplitPane.java index 8099eb2c..10d5eb10 100644 --- a/src/main/java/com/ss/editor/ui/component/split/pane/EditorToolSplitPane.java +++ b/src/main/java/com/ss/builder/fx/component/split/pane/EditorToolSplitPane.java @@ -1,9 +1,9 @@ -package com.ss.editor.ui.component.split.pane; +package com.ss.builder.fx.component.split.pane; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.EditorToolConfig; -import com.ss.editor.ui.component.tab.GlobalLeftToolComponent; -import com.ss.editor.ui.component.tab.TabToolComponent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.state.EditorToolConfig; +import com.ss.builder.fx.component.tab.GlobalLeftToolComponent; +import com.ss.builder.fx.component.tab.TabToolComponent; import com.ss.rlib.fx.util.ObservableUtils; import javafx.scene.Node; import javafx.scene.Scene; diff --git a/src/main/java/com/ss/editor/ui/component/split/pane/GlobalBottomToolSplitPane.java b/src/main/java/com/ss/builder/fx/component/split/pane/GlobalBottomToolSplitPane.java similarity index 88% rename from src/main/java/com/ss/editor/ui/component/split/pane/GlobalBottomToolSplitPane.java rename to src/main/java/com/ss/builder/fx/component/split/pane/GlobalBottomToolSplitPane.java index c565c5bd..6bebb85c 100644 --- a/src/main/java/com/ss/editor/ui/component/split/pane/GlobalBottomToolSplitPane.java +++ b/src/main/java/com/ss/builder/fx/component/split/pane/GlobalBottomToolSplitPane.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.component.split.pane; +package com.ss.builder.fx.component.split.pane; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.tab.TabToolComponent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.component.tab.TabToolComponent; import com.ss.rlib.fx.util.ObservableUtils; import javafx.geometry.Orientation; import javafx.scene.Node; diff --git a/src/main/java/com/ss/editor/ui/component/split/pane/GlobalLeftToolSplitPane.java b/src/main/java/com/ss/builder/fx/component/split/pane/GlobalLeftToolSplitPane.java similarity index 77% rename from src/main/java/com/ss/editor/ui/component/split/pane/GlobalLeftToolSplitPane.java rename to src/main/java/com/ss/builder/fx/component/split/pane/GlobalLeftToolSplitPane.java index d7c09dc0..3bfe896b 100644 --- a/src/main/java/com/ss/editor/ui/component/split/pane/GlobalLeftToolSplitPane.java +++ b/src/main/java/com/ss/builder/fx/component/split/pane/GlobalLeftToolSplitPane.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.component.split.pane; +package com.ss.builder.fx.component.split.pane; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.tab.GlobalLeftToolComponent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.component.tab.GlobalLeftToolComponent; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/component/split/pane/TabToolSplitPane.java b/src/main/java/com/ss/builder/fx/component/split/pane/TabToolSplitPane.java similarity index 95% rename from src/main/java/com/ss/editor/ui/component/split/pane/TabToolSplitPane.java rename to src/main/java/com/ss/builder/fx/component/split/pane/TabToolSplitPane.java index 3cbc332c..2800e43d 100644 --- a/src/main/java/com/ss/editor/ui/component/split/pane/TabToolSplitPane.java +++ b/src/main/java/com/ss/builder/fx/component/split/pane/TabToolSplitPane.java @@ -1,11 +1,13 @@ -package com.ss.editor.ui.component.split.pane; +package com.ss.builder.fx.component.split.pane; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.lang.Math.max; import static java.lang.Math.min; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.component.tab.TabToolComponent; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.tab.TabToolComponent; import com.ss.rlib.fx.util.ObservableUtils; import javafx.scene.Node; import javafx.scene.Scene; diff --git a/src/main/java/com/ss/editor/ui/component/tab/EditorToolComponent.java b/src/main/java/com/ss/builder/fx/component/tab/EditorToolComponent.java similarity index 85% rename from src/main/java/com/ss/editor/ui/component/tab/EditorToolComponent.java rename to src/main/java/com/ss/builder/fx/component/tab/EditorToolComponent.java index 5a8fe71d..814bb8ca 100644 --- a/src/main/java/com/ss/editor/ui/component/tab/EditorToolComponent.java +++ b/src/main/java/com/ss/builder/fx/component/tab/EditorToolComponent.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.component.tab; +package com.ss.builder.fx.component.tab; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import javafx.geometry.Side; import javafx.scene.control.SplitPane; diff --git a/src/main/java/com/ss/editor/ui/component/tab/GlobalBottomToolComponent.java b/src/main/java/com/ss/builder/fx/component/tab/GlobalBottomToolComponent.java similarity index 91% rename from src/main/java/com/ss/editor/ui/component/tab/GlobalBottomToolComponent.java rename to src/main/java/com/ss/builder/fx/component/tab/GlobalBottomToolComponent.java index 45e80d28..9b7048b3 100644 --- a/src/main/java/com/ss/editor/ui/component/tab/GlobalBottomToolComponent.java +++ b/src/main/java/com/ss/builder/fx/component/tab/GlobalBottomToolComponent.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.component.tab; +package com.ss.builder.fx.component.tab; -import com.ss.editor.ui.css.CssIds; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.css.CssIds; import javafx.geometry.Side; import javafx.scene.control.SplitPane; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/component/tab/GlobalLeftToolComponent.java b/src/main/java/com/ss/builder/fx/component/tab/GlobalLeftToolComponent.java similarity index 82% rename from src/main/java/com/ss/editor/ui/component/tab/GlobalLeftToolComponent.java rename to src/main/java/com/ss/builder/fx/component/tab/GlobalLeftToolComponent.java index 99a1f777..9d2a306f 100644 --- a/src/main/java/com/ss/editor/ui/component/tab/GlobalLeftToolComponent.java +++ b/src/main/java/com/ss/builder/fx/component/tab/GlobalLeftToolComponent.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.component.tab; +package com.ss.builder.fx.component.tab; -import com.ss.editor.ui.css.CssIds; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.css.CssIds; import javafx.geometry.Side; import javafx.scene.control.SplitPane; diff --git a/src/main/java/com/ss/editor/ui/component/tab/ScrollableEditorToolComponent.java b/src/main/java/com/ss/builder/fx/component/tab/ScrollableEditorToolComponent.java similarity index 96% rename from src/main/java/com/ss/editor/ui/component/tab/ScrollableEditorToolComponent.java rename to src/main/java/com/ss/builder/fx/component/tab/ScrollableEditorToolComponent.java index d88eac4d..4e2798d2 100644 --- a/src/main/java/com/ss/editor/ui/component/tab/ScrollableEditorToolComponent.java +++ b/src/main/java/com/ss/builder/fx/component/tab/ScrollableEditorToolComponent.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.component.tab; +package com.ss.builder.fx.component.tab; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.control.ScrollPane; diff --git a/src/main/java/com/ss/editor/ui/component/tab/TabToolComponent.java b/src/main/java/com/ss/builder/fx/component/tab/TabToolComponent.java similarity index 98% rename from src/main/java/com/ss/editor/ui/component/tab/TabToolComponent.java rename to src/main/java/com/ss/builder/fx/component/tab/TabToolComponent.java index 33988a67..28ab8abe 100644 --- a/src/main/java/com/ss/editor/ui/component/tab/TabToolComponent.java +++ b/src/main/java/com/ss/builder/fx/component/tab/TabToolComponent.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui.component.tab; +package com.ss.builder.fx.component.tab; -import com.ss.editor.ui.component.ScreenComponent; +import com.ss.builder.fx.component.ScreenComponent; import com.ss.rlib.fx.util.FXUtils; import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTree.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTree.java similarity index 90% rename from src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTree.java rename to src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTree.java index bbd3edb0..0569bf94 100644 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTree.java +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTree.java @@ -1,12 +1,18 @@ -package com.ss.editor.ui.component.virtual.tree; +package com.ss.builder.fx.component.virtual.tree; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.component.virtual.tree.resource.FolderVirtualResourceElement; -import com.ss.editor.ui.component.virtual.tree.resource.VirtualResourceElement; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.virtual.tree.resource.FolderVirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.component.virtual.tree.resource.FolderVirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTreeCell.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTreeCell.java new file mode 100644 index 00000000..ed60e5e1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/VirtualResourceTreeCell.java @@ -0,0 +1,61 @@ +package com.ss.builder.fx.component.virtual.tree; + +import static com.ss.builder.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.fx.component.virtual.tree.resource.FolderVirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.fx.component.virtual.tree.resource.FolderVirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.control.TreeCell; +import javafx.scene.control.TreeView; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The implementation of the cell for {@link TreeView} to show resource. + * + * @author JavaSaBr + */ +public class VirtualResourceTreeCell extends TreeCell> { + + /** + * The icon manager. + */ + @NotNull + private static final FileIconManager ICON_MANAGER = FileIconManager.getInstance(); + + /** + * The icon. + */ + @NotNull + private final ImageView icon; + + protected VirtualResourceTreeCell() { + this.icon = new ImageView(); + } + + @Override + protected void updateItem(@Nullable final VirtualResourceElement item, boolean empty) { + super.updateItem(item, empty); + + if (item == null) { + setText(StringUtils.EMPTY); + setGraphic(null); + return; + } + + final Path file = Paths.get(item.getPath()); + final boolean folder = item instanceof FolderVirtualResourceElement; + + icon.setImage(ICON_MANAGER.getIcon(file, folder, false, FileIconManager.DEFAULT_FILE_ICON_SIZE)); + + setText(item.getName()); + setGraphic(icon); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/FolderVirtualResourceElement.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/FolderVirtualResourceElement.java similarity index 83% rename from src/main/java/com/ss/editor/ui/component/virtual/tree/resource/FolderVirtualResourceElement.java rename to src/main/java/com/ss/builder/fx/component/virtual/tree/resource/FolderVirtualResourceElement.java index f6fdd224..80f84558 100644 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/FolderVirtualResourceElement.java +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/FolderVirtualResourceElement.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.component.virtual.tree.resource; +package com.ss.builder.fx.component.virtual.tree.resource; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/ObjectVirtualResourceElement.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/ObjectVirtualResourceElement.java similarity index 76% rename from src/main/java/com/ss/editor/ui/component/virtual/tree/resource/ObjectVirtualResourceElement.java rename to src/main/java/com/ss/builder/fx/component/virtual/tree/resource/ObjectVirtualResourceElement.java index f12edb63..a49ae1d5 100644 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/ObjectVirtualResourceElement.java +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/ObjectVirtualResourceElement.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui.component.virtual.tree.resource; +package com.ss.builder.fx.component.virtual.tree.resource; -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/RootVirtualResourceElement.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/RootVirtualResourceElement.java new file mode 100644 index 00000000..8a860c45 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/RootVirtualResourceElement.java @@ -0,0 +1,16 @@ +package com.ss.builder.fx.component.virtual.tree.resource; + +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; +import org.jetbrains.annotations.NotNull; + +/** + * The root implementation of the virtual resource element. + * + * @author JavaSaBr + */ +public class RootVirtualResourceElement extends FolderVirtualResourceElement { + + public RootVirtualResourceElement(@NotNull final VirtualResourceTree resourceTree) { + super(resourceTree, "/"); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElement.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElement.java similarity index 92% rename from src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElement.java rename to src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElement.java index 54eb11cb..a7643d8e 100644 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElement.java +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElement.java @@ -1,8 +1,9 @@ -package com.ss.editor.ui.component.virtual.tree.resource; +package com.ss.builder.fx.component.virtual.tree.resource; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElementFactory.java b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElementFactory.java similarity index 94% rename from src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElementFactory.java rename to src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElementFactory.java index d44dfd6b..914ef7f6 100644 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/VirtualResourceElementFactory.java +++ b/src/main/java/com/ss/builder/fx/component/virtual/tree/resource/VirtualResourceElementFactory.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.component.virtual.tree.resource; +package com.ss.builder.fx.component.virtual.tree.resource; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/ui/control/UpdatableControl.java b/src/main/java/com/ss/builder/fx/control/UpdatableControl.java similarity index 84% rename from src/main/java/com/ss/editor/ui/control/UpdatableControl.java rename to src/main/java/com/ss/builder/fx/control/UpdatableControl.java index c08f699b..d8b2beb9 100644 --- a/src/main/java/com/ss/editor/ui/control/UpdatableControl.java +++ b/src/main/java/com/ss/builder/fx/control/UpdatableControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control; +package com.ss.builder.fx.control; /** * The interface to implement an updatable control. diff --git a/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateList.java b/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateList.java new file mode 100644 index 00000000..5bc23c4f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateList.java @@ -0,0 +1,253 @@ +package com.ss.builder.fx.control.app.state.list; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveAppStateOperation; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.action.MenuModifyingAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.CreateSceneAppStateDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.JmbEditorEnvoriment; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.app.state.EditableSceneAppState; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveAppStateOperation; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.action.MenuModifyingAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.CreateSceneAppStateDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.util.JmbEditorEnvoriment; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.ListView; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * The component to show and to edit app states. + * + * @author JavaSaBr + */ +public class AppStateList extends VBox { + + /** + * The selection handler. + */ + @NotNull + private final Consumer selectHandler; + + /** + * The changes consumer. + */ + @NotNull + private final SceneChangeConsumer changeConsumer; + + /** + * The list view with created scene app states. + */ + @Nullable + private ListView listView; + + public AppStateList( + @NotNull Consumer selectHandler, + @NotNull SceneChangeConsumer changeConsumer + ) { + this.changeConsumer = changeConsumer; + this.selectHandler = selectHandler; + createComponents(); + FxUtils.addClass(this, CssClasses.SCENE_APP_STATE_CONTAINER); + } + + /** + * Create components of this component. + */ + @FxThread + private void createComponents() { + + listView = new ListView<>(); + listView.setCellFactory(param -> new AppStateListCell(this)); + listView.setFocusTraversable(true); + listView.setEditable(true); + listView.prefHeightProperty().bind(heightProperty()); + listView.prefWidthProperty().bind(widthProperty()); + listView.setFixedCellSize(FxConstants.LIST_CELL_HEIGHT); + + FxControlUtils.onSelectedItemChange(listView, selectHandler); + + var selectionModel = listView.getSelectionModel(); + + var addButton = new Button(); + addButton.setGraphic(new ImageView(Icons.ADD_12)); + addButton.setOnAction(event -> addAppState()); + + var removeButton = new Button(); + removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); + removeButton.setOnAction(event -> removeAppState()); + removeButton.disableProperty().bind(selectionModel.selectedItemProperty().isNull()); + + var buttonContainer = new HBox(addButton, removeButton); + + FxUtils.addClass(buttonContainer, CssClasses.DEF_HBOX) + .addClass(addButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER) + .addClass(removeButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER) + .addClass(listView, CssClasses.TRANSPARENT_LIST_VIEW); + + FxUtils.addChild(this, listView, buttonContainer); + + DynamicIconSupport.addSupport(addButton, removeButton); + } + + /** + * Fill a list of app states. + * + * @param sceneNode the scene node + */ + @FxThread + public void fill(@NotNull SceneNode sceneNode) { + + var listView = getListView(); + var selectionModel = listView.getSelectionModel(); + var selected = selectionModel.getSelectedItem(); + + var items = listView.getItems(); + items.clear(); + + var appStates = sceneNode.getAppStates(); + appStates.stream() + .filter(EditableSceneAppState.class::isInstance) + .map(EditableSceneAppState.class::cast) + .forEach(items::add); + + if (selected != null && appStates.contains(selected)) { + selectionModel.select(selected); + } + } + + /** + * Get a context menu for the app state. + * + * @param appState the requested app state. + * @return the context menu or null. + */ + @FxThread + protected @Nullable ContextMenu getContextMenu(@Nullable SceneAppState appState) { + + if (!(appState instanceof EditableSceneAppState)) { + return null; + } + + var actions = ((EditableSceneAppState) appState) + .getModifyingActions(JmbEditorEnvoriment.getInstance()); + + if (actions.isEmpty()) { + return null; + } + + var contextMenu = new ContextMenu(); + var items = contextMenu.getItems(); + + actions.stream() + .map(action -> new MenuModifyingAction(action, getChangeConsumer(), appState)) + .forEach(items::add); + + return contextMenu; + } + + /** + * Refresh the app state. + * + * @param appState the app state. + */ + @FxThread + public void refresh(@NotNull EditableSceneAppState appState) { + + var items = getListView().getItems(); + var index = items.indexOf(appState); + + if (index != -1) { + items.add(index, appState); + items.remove(index + 1); + } + } + + /** + * Get the list view with created scene app states. + * + * @return the list view with created scene app states. + */ + @FxThread + private @NotNull ListView getListView() { + return notNull(listView); + } + + /** + * Clear selection. + */ + @FxThread + public void clearSelection() { + getListView().getSelectionModel() + .select(null); + } + + /** + * Get the current selected item. + * + * @return the current selected item. + */ + @FxThread + public @Nullable EditableSceneAppState getSelected() { + return getListView() + .getSelectionModel() + .getSelectedItem(); + } + + /** + * Handle adding a new app state. + */ + @FxThread + private void addAppState() { + var dialog = new CreateSceneAppStateDialog(changeConsumer); + dialog.show(); + } + + /** + * Handle removing an old app state. + */ + @FxThread + private void removeAppState() { + + var appState = getListView() + .getSelectionModel() + .getSelectedItem(); + + var sceneNode = changeConsumer.getCurrentModel(); + + changeConsumer.execute(new RemoveAppStateOperation(appState, sceneNode)); + } + + /** + * Get the change consumer. + * + * @return the changes consumer. + */ + @FromAnyThread + public @NotNull SceneChangeConsumer getChangeConsumer() { + return changeConsumer; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateListCell.java b/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateListCell.java new file mode 100644 index 00000000..9ba755dc --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/app/state/list/AppStateListCell.java @@ -0,0 +1,73 @@ +package com.ss.builder.fx.control.app.state.list; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.impl.DisableAppStateOperation; +import com.ss.builder.model.undo.impl.EnableAppStateOperation; +import com.ss.builder.fx.control.list.AbstractListCell; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.app.state.EditableSceneAppState; +import com.ss.builder.model.undo.impl.DisableAppStateOperation; +import com.ss.builder.model.undo.impl.EnableAppStateOperation; +import com.ss.builder.fx.control.list.AbstractListCell; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of list cell to present an editable scene app state. + * + * @author JavaSaBr + */ +public class AppStateListCell extends AbstractListCell { + + /** + * The list of app states. + */ + @NotNull + private final AppStateList stateList; + + public AppStateListCell(@NotNull AppStateList stateList) { + super(stateList.getChangeConsumer(), stateList::getContextMenu); + this.stateList = stateList; + FxUtils.addClass(this, CssClasses.SCENE_APP_STATE_LIST_CELL); + } + + /** + * Get the list of app states. + * + * @return the list of app states. + */ + @FxThread + private @NotNull AppStateList getStateList() { + return stateList; + } + + @Override + @FxThread + protected void processHideImpl() { + + var item = getItem(); + var stateList = getStateList(); + var changeConsumer = stateList.getChangeConsumer(); + + if (item.isEnabled()) { + changeConsumer.execute(new DisableAppStateOperation(item)); + } else { + changeConsumer.execute(new EnableAppStateOperation(item)); + } + } + + @Override + @FxThread + protected boolean isEnabled(@Nullable EditableSceneAppState item) { + return item != null && item.isEnabled(); + } + + @Override + @FxThread + protected @NotNull String getName(@Nullable EditableSceneAppState item) { + return item == null ? "" : item.getName(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/choose/ChooseFolderControl.java b/src/main/java/com/ss/builder/fx/control/choose/ChooseFolderControl.java similarity index 77% rename from src/main/java/com/ss/editor/ui/control/choose/ChooseFolderControl.java rename to src/main/java/com/ss/builder/fx/control/choose/ChooseFolderControl.java index 88190a6c..eb4d88b9 100644 --- a/src/main/java/com/ss/editor/ui/control/choose/ChooseFolderControl.java +++ b/src/main/java/com/ss/builder/fx/control/choose/ChooseFolderControl.java @@ -1,16 +1,26 @@ -package com.ss.editor.ui.control.choose; +package com.ss.builder.fx.control.choose; -import static com.ss.editor.util.EditorUtil.getAssetFile; +import static com.ss.builder.util.EditorUtils.getAssetFile; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.StringUtils; import javafx.scene.control.Button; @@ -171,7 +181,7 @@ protected void reload() { return; } - final Path assetFile = notNull(getAssetFile(folder)); + final Path assetFile = notNull(EditorUtils.getAssetFile(folder)); folderLabel.setText(assetFile.toString()); } } diff --git a/src/main/java/com/ss/editor/ui/control/choose/ChooseTextureControl.java b/src/main/java/com/ss/builder/fx/control/choose/ChooseTextureControl.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/choose/ChooseTextureControl.java rename to src/main/java/com/ss/builder/fx/control/choose/ChooseTextureControl.java index c0eb701d..14f4a37e 100644 --- a/src/main/java/com/ss/editor/ui/control/choose/ChooseTextureControl.java +++ b/src/main/java/com/ss/builder/fx/control/choose/ChooseTextureControl.java @@ -1,19 +1,32 @@ -package com.ss.editor.ui.control.choose; +package com.ss.builder.fx.control.choose; -import static com.ss.editor.FileExtensions.TEXTURE_EXTENSIONS; -import static com.ss.editor.util.EditorUtil.getAssetFile; +import static com.ss.builder.FileExtensions.TEXTURE_EXTENSIONS; +import static com.ss.builder.util.EditorUtils.getAssetFile; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.JavaFxImageManager; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.tooltip.ImageChannelPreview; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.tooltip.ImageChannelPreview; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.tooltip.ImageChannelPreview; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -92,7 +105,7 @@ public ChooseTextureControl() { */ @FxThread private void dragDropped(@NotNull final DragEvent dragEvent) { - UiUtils.handleDroppedFile(dragEvent, TEXTURE_EXTENSIONS, this, ChooseTextureControl::setTextureFile); + UiUtils.handleDroppedFile(dragEvent, this, ChooseTextureControl::setTextureFile); } /** @@ -100,7 +113,7 @@ private void dragDropped(@NotNull final DragEvent dragEvent) { */ @FxThread private void dragOver(@NotNull final DragEvent dragEvent) { - UiUtils.acceptIfHasFile(dragEvent, TEXTURE_EXTENSIONS); + UiUtils.acceptIfHasFile(dragEvent, FileExtensions.TEXTURE_EXTENSIONS); } /** @@ -202,7 +215,7 @@ protected void createComponents() { */ @FxThread private void processAdd() { - UiUtils.openFileAssetDialog(this::setTextureFile, TEXTURE_EXTENSIONS, ACTION_TESTER); + UiUtils.openFileAssetDialog(this::setTextureFile, FileExtensions.TEXTURE_EXTENSIONS, ACTION_TESTER); } /** @@ -267,7 +280,7 @@ protected void reload() { return; } - final Path assetFile = notNull(getAssetFile(textureFile)); + final Path assetFile = notNull(EditorUtils.getAssetFile(textureFile)); textureLabel.setText(assetFile.toString()); preview.setImage(IMAGE_MANAGER.getImagePreview(textureFile, 28, 28)); diff --git a/src/main/java/com/ss/editor/ui/control/choose/NamedChooseTextureControl.java b/src/main/java/com/ss/builder/fx/control/choose/NamedChooseTextureControl.java similarity index 91% rename from src/main/java/com/ss/editor/ui/control/choose/NamedChooseTextureControl.java rename to src/main/java/com/ss/builder/fx/control/choose/NamedChooseTextureControl.java index 7e1a587a..fe7ba399 100644 --- a/src/main/java/com/ss/editor/ui/control/choose/NamedChooseTextureControl.java +++ b/src/main/java/com/ss/builder/fx/control/choose/NamedChooseTextureControl.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.control.choose; +package com.ss.builder.fx.control.choose; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.property.PropertyControl; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.property.PropertyControl; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.StringUtils; import javafx.scene.control.Label; diff --git a/src/main/java/com/ss/editor/ui/control/code/BaseCodeArea.java b/src/main/java/com/ss/builder/fx/control/code/BaseCodeArea.java similarity index 98% rename from src/main/java/com/ss/editor/ui/control/code/BaseCodeArea.java rename to src/main/java/com/ss/builder/fx/control/code/BaseCodeArea.java index 9be7b032..b1a0ab87 100644 --- a/src/main/java/com/ss/editor/ui/control/code/BaseCodeArea.java +++ b/src/main/java/com/ss/builder/fx/control/code/BaseCodeArea.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.control.code; +package com.ss.builder.fx.control.code; import static java.util.Collections.singleton; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.StringUtils; import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.model.StyleSpans; diff --git a/src/main/java/com/ss/editor/ui/control/code/GLSLCodeArea.java b/src/main/java/com/ss/builder/fx/control/code/GLSLCodeArea.java similarity index 93% rename from src/main/java/com/ss/editor/ui/control/code/GLSLCodeArea.java rename to src/main/java/com/ss/builder/fx/control/code/GLSLCodeArea.java index 324b7ffa..0b76fa06 100644 --- a/src/main/java/com/ss/editor/ui/control/code/GLSLCodeArea.java +++ b/src/main/java/com/ss/builder/fx/control/code/GLSLCodeArea.java @@ -1,7 +1,9 @@ -package com.ss.editor.ui.control.code; +package com.ss.builder.fx.control.code; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.util.GlslType; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.GlslType; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.GlslType; import org.fxmisc.richtext.model.StyleSpans; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/ui/control/code/MaterialDefinitionCodeArea.java b/src/main/java/com/ss/builder/fx/control/code/MaterialDefinitionCodeArea.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/code/MaterialDefinitionCodeArea.java rename to src/main/java/com/ss/builder/fx/control/code/MaterialDefinitionCodeArea.java index d5953cca..cbddad52 100644 --- a/src/main/java/com/ss/editor/ui/control/code/MaterialDefinitionCodeArea.java +++ b/src/main/java/com/ss/builder/fx/control/code/MaterialDefinitionCodeArea.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.control.code; +package com.ss.builder.fx.control.code; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import org.fxmisc.richtext.model.StyleSpans; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java b/src/main/java/com/ss/builder/fx/control/filter/list/FilterList.java similarity index 86% rename from src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java rename to src/main/java/com/ss/builder/fx/control/filter/list/FilterList.java index 49ddd6ce..018b65d3 100644 --- a/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java +++ b/src/main/java/com/ss/builder/fx/control/filter/list/FilterList.java @@ -1,16 +1,24 @@ -package com.ss.editor.ui.control.filter.list; - -import com.ss.editor.annotation.FxThread; +package com.ss.builder.fx.control.filter.list; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveSceneFilterOperation; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.CreateSceneFilterDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.filter.EditableSceneFilter; import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.dialog.CreateSceneFilterDialog; -import com.ss.editor.model.undo.impl.RemoveSceneFilterOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.CreateSceneFilterDialog; +import com.ss.builder.model.undo.impl.RemoveSceneFilterOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; import com.ss.rlib.fx.util.FXUtils; import javafx.collections.ObservableList; import javafx.scene.control.Button; diff --git a/src/main/java/com/ss/builder/fx/control/filter/list/FilterListCell.java b/src/main/java/com/ss/builder/fx/control/filter/list/FilterListCell.java new file mode 100644 index 00000000..f90c981f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/filter/list/FilterListCell.java @@ -0,0 +1,77 @@ +package com.ss.builder.fx.control.filter.list; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.DisableSceneFilterOperation; +import com.ss.builder.model.undo.impl.EnableSceneFilterOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.filter.EditableSceneFilter; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.DisableSceneFilterOperation; +import com.ss.builder.model.undo.impl.EnableSceneFilterOperation; +import com.ss.builder.fx.control.list.AbstractListCell; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FXUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of list cell to present an editable scene filter. + * + * @author JavaSaBr + */ +public class FilterListCell extends AbstractListCell { + + /** + * The list of filters. + */ + @NotNull + private final FilterList stateList; + + /** + * Instantiates a new Filter list cell. + * + * @param stateList the state list + */ + public FilterListCell(@NotNull final FilterList stateList) { + super(stateList.getChangeConsumer(), filter -> null); + this.stateList = stateList; + FXUtils.addClassTo(this, CssClasses.SCENE_FILTER_LIST_CELL); + } + + /** + * @return the list of app states. + */ + @NotNull + private FilterList getStateList() { + return stateList; + } + + @FxThread + @Override + protected void processHideImpl() { + + final EditableSceneFilter item = getItem(); + final FilterList stateList = getStateList(); + final SceneChangeConsumer changeConsumer = stateList.getChangeConsumer(); + + if (item.isEnabled()) { + changeConsumer.execute(new DisableSceneFilterOperation(item)); + } else { + changeConsumer.execute(new EnableSceneFilterOperation(item)); + } + } + + @FxThread + @Override + protected boolean isEnabled(@Nullable final EditableSceneFilter item) { + return item != null && item.isEnabled(); + } + + @NotNull + @Override + protected String getName(@Nullable final EditableSceneFilter item) { + return item == null ? "" : item.getName(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java b/src/main/java/com/ss/builder/fx/control/layer/LayerNodeTree.java similarity index 88% rename from src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java rename to src/main/java/com/ss/builder/fx/control/layer/LayerNodeTree.java index ffae22fa..18c67ec4 100644 --- a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java +++ b/src/main/java/com/ss/builder/fx/control/layer/LayerNodeTree.java @@ -1,13 +1,15 @@ -package com.ss.editor.ui.control.layer; +package com.ss.builder.fx.control.layer; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; +import static com.ss.builder.fx.util.UiUtils.findItemForValue; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.NodeTreeCell; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.NodeTreeCell; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.array.Array; import javafx.scene.control.SelectionMode; import javafx.scene.control.TreeItem; diff --git a/src/main/java/com/ss/builder/fx/control/layer/LayerNodeTreeCell.java b/src/main/java/com/ss/builder/fx/control/layer/LayerNodeTreeCell.java new file mode 100644 index 00000000..3c885183 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/layer/LayerNodeTreeCell.java @@ -0,0 +1,18 @@ +package com.ss.builder.fx.control.layer; + +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTreeCell; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link NodeTreeCell} to show layer nodes. + * + * @author JavaSaBr + */ +public class LayerNodeTreeCell extends NodeTreeCell { + + public LayerNodeTreeCell(@NotNull final LayerNodeTree nodeTree) { + super(nodeTree); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/list/AbstractListCell.java b/src/main/java/com/ss/builder/fx/control/list/AbstractListCell.java new file mode 100644 index 00000000..9e8e2362 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/list/AbstractListCell.java @@ -0,0 +1,197 @@ +package com.ss.builder.fx.control.list; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.RenameEditableNameOperation; +import com.ss.editor.extension.EditableName; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.geometry.Side; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.Label; +import javafx.scene.control.cell.TextFieldListCell; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.util.StringConverter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +/** + * The base implementation of list cell. + * + * @author JavaSaBr + */ +public abstract class AbstractListCell extends TextFieldListCell { + + @NotNull + private final StringConverter stringConverter = new StringConverter<>() { + + @Override + public String toString(@Nullable T object) { + return getName(object); + } + + @Override + public T fromString(@NotNull String newName) { + + var item = getItem(); + if (item == null) { + return null; + } + + var object = (EditableName) item; + var currentName = object.getName(); + + changeConsumer.execute(new RenameEditableNameOperation(currentName, newName, object)); + + return item; + } + }; + + /** + * The content box. + */ + @NotNull + private final HBox content; + + /** + * The label of this cell. + */ + @NotNull + private final Label text; + + /** + * The visible icon. + */ + @NotNull + private final ImageView visibleIcon; + + /** + * The change consumer. + */ + @NotNull + private final ChangeConsumer changeConsumer; + + /** + * The context menu factory. + */ + @NotNull + private final Function contextMenuFactory; + + public AbstractListCell( + @NotNull ChangeConsumer changeConsumer, + @NotNull Function contextMenuFactory + ) { + this.changeConsumer = changeConsumer; + this.contextMenuFactory = contextMenuFactory; + this.content = new HBox(); + this.text = new Label(); + this.visibleIcon = new ImageView(); + this.visibleIcon.addEventFilter(MouseEvent.MOUSE_RELEASED, this::processHide); + this.visibleIcon.setOnMouseReleased(this::processHide); + this.visibleIcon.setPickOnBounds(true); + + setOnMouseClicked(this::processClick); + setConverter(stringConverter); + + FxUtils.addClass(content, CssClasses.DEF_HBOX); + FxUtils.addChild(content, visibleIcon, text); + + setEditable(false); + } + + /** + * Handle a mouse click. + */ + @FxThread + private void processClick(@NotNull MouseEvent event) { + + T item = getItem(); + if (item == null) { + return; + } + + var button = event.getButton(); + if (button != MouseButton.SECONDARY) { + return; + } + + var contextMenu = contextMenuFactory.apply(item); + if (contextMenu == null) { + return; + } + + ExecutorManager.getInstance() + .addFxTask(() -> contextMenu.show(this, Side.BOTTOM, 0, 0)); + } + + /** + * Update hide status. + */ + @FxThread + private void processHide(@NotNull MouseEvent event) { + event.consume(); + + if (event.getButton() != MouseButton.PRIMARY) { + return; + } + + processHideImpl(); + } + + /** + * Process to hide. + */ + @FxThread + protected abstract void processHideImpl(); + + @Override + @FxThread + public void updateItem(@Nullable T item, boolean empty) { + super.updateItem(item, empty); + + if (item == null) { + setText(StringUtils.EMPTY); + setGraphic(null); + setEditable(false); + return; + } + + visibleIcon.setVisible(true); + visibleIcon.setManaged(true); + visibleIcon.setImage(!isEnabled(item) ? Icons.INVISIBLE_16 : Icons.VISIBLE_16); + visibleIcon.setOpacity(!isEnabled(item) ? 0.5D : 1D); + + DynamicIconSupport.updateListener(this, visibleIcon, selectedProperty()); + + text.setText(getName(item)); + + setText(StringUtils.EMPTY); + setGraphic(content); + setEditable(item instanceof EditableName); + } + + /** + * Get the name of the item. + * + * @param item the item. + * @return the name. + */ + @FxThread + protected abstract @NotNull String getName(@Nullable T item); + + /** + * @param item the item which needs to check. + * @return true if the item is enabled. + */ + @FxThread + protected abstract boolean isEnabled(@Nullable T item); +} diff --git a/src/main/java/com/ss/builder/fx/control/model/ModelNodeTree.java b/src/main/java/com/ss/builder/fx/control/model/ModelNodeTree.java new file mode 100644 index 00000000..5821edce --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/model/ModelNodeTree.java @@ -0,0 +1,36 @@ +package com.ss.builder.fx.control.model; + +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.multi.RemoveElementsAction; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.control.SelectionMode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * The implementation of {@link NodeTree} to present a structure of model in an editor. + * + * @author JavaSaBr + */ +public class ModelNodeTree extends NodeTree { + + static { + register(RemoveElementsAction.ACTION_FILLER); + } + + public ModelNodeTree(@NotNull Consumer> selectionHandler, @Nullable ModelChangeConsumer consumer) { + super(selectionHandler, consumer, SelectionMode.MULTIPLE); + } + + public ModelNodeTree( + @NotNull Consumer> selectionHandler, + @Nullable ModelChangeConsumer consumer, + @NotNull SelectionMode selectionMode + ) { + super(selectionHandler, consumer, selectionMode); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/model/ModelPropertyEditor.java b/src/main/java/com/ss/builder/fx/control/model/ModelPropertyEditor.java new file mode 100644 index 00000000..55d0fdf2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/model/ModelPropertyEditor.java @@ -0,0 +1,102 @@ +package com.ss.builder.fx.control.model; + +import static com.ss.builder.util.NodeUtils.findParent; +import com.jme3.material.Material; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.PropertyEditor; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.PropertyEditor; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The component to contains property controls in the editor. + * + * @author JavaSaBr + */ +public class ModelPropertyEditor extends PropertyEditor { + + @FunctionalInterface + public interface IsNeedUpdateChecker { + + @FxThread + boolean isNeedUpdate(@Nullable Object currentObject, @Nullable Object changedObject); + } + + @FunctionalInterface + public interface CanEditChecker { + + @FxThread + boolean canEdit(@Nullable Object object, @Nullable Object parent); + } + + /** + * @see IsNeedUpdateChecker + */ + public static final String EP_NEED_UPDATE_CHECKERS = "ModelPropertyEditor#needUpdateCheckers"; + + /** + * @see CanEditChecker + */ + public static final String EP_CAN_EDIT_CHECKERS = "ModelPropertyEditor#canEditCheckers"; + + private static final ExtensionPoint NEED_UPDATE_CHECKERS = + ExtensionPointManager.register(EP_NEED_UPDATE_CHECKERS); + + private static final ExtensionPoint CAN_EDIT_CHECKERS = + ExtensionPointManager.register(EP_CAN_EDIT_CHECKERS); + + public ModelPropertyEditor(@NotNull ModelChangeConsumer changeConsumer) { + super(changeConsumer); + } + + @Override + @FxThread + protected boolean isNeedUpdate(@Nullable Object changedObject) { + + var currentObject = getCurrentObject(); + + if (changedObject instanceof EditableProperty) { + changedObject = ((EditableProperty) changedObject).getObject(); + } + + return NEED_UPDATE_CHECKERS.anyMatch(currentObject, changedObject, + IsNeedUpdateChecker::isNeedUpdate) || super.isNeedUpdate(changedObject); + } + + @Override + @FxThread + protected boolean canEdit(@NotNull Object object, @Nullable Object parent) { + + if (object instanceof Control) { + return true; + } else if (object instanceof Material) { + + var material = (Material) object; + + if (material.getKey() != null) { + return false; + } + + } else if (object instanceof Spatial) { + var linkNode = NodeUtils.findParent((Spatial) object, AssetLinkNode.class::isInstance); + return linkNode == null || linkNode == object; + } else if (parent instanceof Spatial) { + var linkNode = NodeUtils.findParent((Spatial) parent, AssetLinkNode.class::isInstance); + return linkNode == null; + } else if(CAN_EDIT_CHECKERS.anyMatchNot(object, parent, CanEditChecker::canEdit)) { + return false; + } + + return super.canEdit(object, parent); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/PropertyControl.java similarity index 80% rename from src/main/java/com/ss/editor/ui/control/property/PropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/PropertyControl.java index 928cd23c..6aae2ae8 100644 --- a/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/PropertyControl.java @@ -1,24 +1,31 @@ -package com.ss.editor.ui.control.property; +package com.ss.builder.fx.control.property; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.JavaFxImageManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.control.UpdatableControl; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.control.UpdatableControl; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.function.SixObjectConsumer; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.fx.util.FxUtils; import javafx.geometry.Pos; +import javafx.scene.Parent; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; @@ -41,6 +48,8 @@ */ public class PropertyControl extends VBox implements UpdatableControl { + protected static final Logger LOGGER = LoggerManager.getLogger(PropertyControl.class); + /** * @param the type of a change consumer. * @param the type of an editing object. @@ -50,51 +59,24 @@ public class PropertyControl extends VBox implem public interface ChangeHandler extends SixObjectConsumer> { } - /** - * The constant LOGGER. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(PropertyControl.class); - - /** - * Default action tester. - */ - @NotNull - protected static final Predicate> DEFAULT_ACTION_TESTER = type -> type == NewFileAction.class || - type == DeleteFileAction.class || type == RenameFileAction.class; + protected static final Predicate> DEFAULT_ACTION_TESTER = + type -> type == NewFileAction.class || + type == DeleteFileAction.class || + type == RenameFileAction.class; - /** - * The constant CONTROL_WIDTH_PERCENT. - */ public static final double CONTROL_WIDTH_PERCENT = 0.4; - - /** - * The constant CONTROL_WIDTH_PERCENT_2. - */ public static final double CONTROL_WIDTH_PERCENT_2 = 0.6; - - /** - * The constant CONTROL_WIDTH_PERCENT_3. - */ public static final double CONTROL_WIDTH_PERCENT_3 = 0.7; - /** - * The FX event manager. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * The executor manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The image preview manager. - */ - @NotNull - protected static final JavaFxImageManager IMAGE_MANAGER = JavaFxImageManager.getInstance(); + @FxThread + public static void constructProperties(@NotNull Parent parent) { + parent.getChildrenUnmodifiable() + .stream() + .filter(PropertyControl.class::isInstance) + .map(node -> (PropertyControl) node) + .peek(PropertyControl::postConstruct) + .forEach(PropertyControl::reload); + } /** * The change handler. @@ -114,6 +96,12 @@ public interface ChangeHandler extends SixObjectConsumer extends SixObjectConsumer syncHandler; /** - * The label of the property name. + * The flag for ignoring listeners. */ - @Nullable - private Label propertyNameLabel; + private boolean ignoreListener; /** - * The flag for ignoring listeners. + * The flag to mark this control that this control was constructed fully. */ - private boolean ignoreListener; + private boolean constructed; public PropertyControl(@Nullable T propertyValue, @NotNull String propertyName, @NotNull C changeConsumer) { this(propertyValue, propertyName, changeConsumer, null); @@ -162,17 +149,11 @@ public PropertyControl( this.propertyName = propertyName; this.changeConsumer = changeConsumer; this.changeHandler = changeHandler == null ? newChangeHandler() : changeHandler; + this.propertyNameLabel = new Label(getPropertyName() + ":"); setOnKeyReleased(UiUtils::consumeIfIsNotHotKey); setOnKeyPressed(UiUtils::consumeIfIsNotHotKey); setPropertyValue(propertyValue); - createComponents(); - setIgnoreListener(true); - try { - reload(); - } finally { - setIgnoreListener(false); - } } /** @@ -211,15 +192,8 @@ public void setEditObject(@NotNull D editObject) { public void setEditObject(@NotNull D editObject, boolean needReload) { setEditObject(editObject); - if (!needReload) { - return; - } - - setIgnoreListener(true); - try { + if (needReload) { reload(); - } finally { - setIgnoreListener(false); } } @@ -277,7 +251,20 @@ protected boolean hasEditObject() { * Reloading control. */ @FxThread - protected void reload() { + public void reload() { + setIgnoreListener(true); + try { + reloadImpl(); + } finally { + setIgnoreListener(false); + } + } + + /** + * Reloading control. + */ + @FxThread + protected void reloadImpl() { } /** @@ -325,7 +312,7 @@ public void sync() { } if (!Objects.equals(currentValue, getPropertyValue())) { - reload(); + reloadImpl(); } } finally { @@ -334,20 +321,25 @@ public void sync() { } /** - * Create this control. + * Create all necessary things after constructor. */ @FxThread - protected void createComponents() { + public void postConstruct() { + + if (constructed) { + return; + } else { + constructed = true; + } + setAlignment(isSingleRow() ? Pos.CENTER_RIGHT : Pos.CENTER); var container = new HBox(); container.setAlignment(isSingleRow() ? Pos.CENTER_RIGHT : Pos.CENTER); - propertyNameLabel = new Label(getPropertyName() + ":"); - if (isSingleRow()) { propertyNameLabel.maxWidthProperty() - .bind(widthProperty().multiply(1F - CONTROL_WIDTH_PERCENT)); + .bind(widthProperty().multiply(1F - CONTROL_WIDTH_PERCENT)); } FxUtils.addClass(container, CssClasses.DEF_HBOX) @@ -355,7 +347,7 @@ protected void createComponents() { FxUtils.addChild(isSingleRow() ? container : this, propertyNameLabel); - createComponents(container); + createControls(container); FxUtils.addChild(this, container); } @@ -366,16 +358,6 @@ protected void createComponents() { CssClasses.ABSTRACT_PARAM_CONTROL_PARAM_NAME; } - /** - * Get the property name label. - * - * @return the property name label. - */ - @FxThread - protected @NotNull Label getPropertyNameLabel() { - return propertyNameLabel; - } - /** * Change control width percent. * @@ -388,10 +370,9 @@ public void changeControlWidthPercent(double controlWidthPercent) { return; } - var propertyNameLabel = getPropertyNameLabel(); propertyNameLabel.maxWidthProperty().unbind(); propertyNameLabel.maxWidthProperty() - .bind(widthProperty().multiply(1D - controlWidthPercent)); + .bind(widthProperty().multiply(1D - controlWidthPercent)); } /** @@ -410,7 +391,7 @@ protected boolean isSingleRow() { * @param container the container. */ @FxThread - protected void createComponents(@NotNull HBox container) { + protected void createControls(@NotNull HBox container) { } /** diff --git a/src/main/java/com/ss/builder/fx/control/property/PropertyEditor.java b/src/main/java/com/ss/builder/fx/control/property/PropertyEditor.java new file mode 100644 index 00000000..31ec4b22 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/PropertyEditor.java @@ -0,0 +1,240 @@ +package com.ss.builder.fx.control.property; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.control.property.builder.PropertyBuilderRegistry; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.control.UpdatableControl; +import com.ss.builder.fx.control.property.builder.PropertyBuilderRegistry; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The component to contains property controls in the editor. + * + * @param the type of {@link ChangeConsumer} + * @author JavaSaBr + */ +public class PropertyEditor extends ScrollPane { + + /** + * The consumer of changes. + */ + @NotNull + private final C changeConsumer; + + /** + * The container of controls. + */ + @NotNull + private final VBox container; + + /** + * The current editable object. + */ + @Nullable + private Object currentObject; + + /** + * The current parent. + */ + @Nullable + private Object currentParent; + + public PropertyEditor(@NotNull C changeConsumer) { + this.changeConsumer = changeConsumer; + this.container = new VBox(); + construct(); + } + + /** + * Finish constructing this property editor. + */ + @FxThread + public void construct() { + + this.container.prefWidthProperty() + .bind(widthProperty().subtract(FxConstants.PROPERTY_LIST_OFFSET)); + + var wrapper = new VBox(container); + + FxUtils.addClass(this, CssClasses.PROPERTY_EDITOR) + .addClass(wrapper, container, CssClasses.DEF_VBOX, CssClasses.PROPERTY_EDITOR_CONTAINER); + + setContent(wrapper); + } + + /** + * Sync all property controls. + * + * @param object the object. + */ + @FxThread + public void syncFor(@Nullable Object object) { + + if (!isNeedUpdate(object)) { + return; + } + + container.setDisable(object == null || !canEdit(object, getCurrentParent())); + container.getChildren().forEach(node -> { + if (node instanceof UpdatableControl) { + ((UpdatableControl) node).sync(); + } + }); + } + + /** + * Sync all property controls. + */ + @FxThread + public void refresh() { + + var object = getCurrentObject(); + if (object == null) { + return; + } + + container.setDisable(!canEdit(object, getCurrentParent())); + container.getChildren().forEach(node -> { + if (node instanceof UpdatableControl) { + ((UpdatableControl) node).sync(); + } + }); + } + + /** + * Build property controls for the object. + * + * @param object the object + * @param parent the parent + */ + @FxThread + public void buildFor(@Nullable Object object, @Nullable Object parent) { + + if (getCurrentObject() == object) { + return; + } + + var children = container.getChildren(); + children.clear(); + + if (object != null) { + PropertyBuilderRegistry.getInstance() + .buildFor(object, parent, container, changeConsumer); + } + + container.setDisable(object == null || !canEdit(object, parent)); + + setCurrentObject(object); + setCurrentParent(parent); + } + + /** + * Return true if we can edit properties of the object. + * + * @param object the object to edit. + * @param parent the parent. + * @return true if we can edit properties of the object. + */ + @FxThread + protected boolean canEdit(@NotNull Object object, @Nullable Object parent) { + return true; + } + + /** + * Re-build property controls for the object. + * + * @param object the object. + * @param parent the parent. + */ + @FxThread + public void rebuildFor(@Nullable Object object, @Nullable Object parent) { + + if (getCurrentObject() != object) { + return; + } + + var children = container.getChildren(); + children.clear(); + + if (object != null) { + PropertyBuilderRegistry.getInstance() + .buildFor(object, parent, container, changeConsumer); + } + } + + /** + * Rebuild all property controls. + */ + @FxThread + public void rebuild() { + rebuildFor(getCurrentObject(), null); + } + + /** + * Return true if need to update property controls. + * + * @param changedObject the changed object. + * @return true if need to update property controls. + */ + @FxThread + protected boolean isNeedUpdate(@Nullable Object changedObject) { + + var currentObject = getCurrentObject(); + if (changedObject instanceof EditableProperty) { + return currentObject == ((EditableProperty) changedObject).getObject(); + } + + return currentObject == changedObject; + } + + /** + * Set the current editable object. + * + * @param currentObject the current editable object. + */ + @FxThread + private void setCurrentObject(@Nullable Object currentObject) { + this.currentObject = currentObject; + } + + /** + * Get the current object. + * + * @return the current editable object. + */ + @FxThread + protected @Nullable Object getCurrentObject() { + return currentObject; + } + + /** + * Set the current parent. + * + * @param currentParent the current parent. + */ + @FxThread + protected void setCurrentParent(@Nullable Object currentParent) { + this.currentParent = currentParent; + } + + /** + * Get the current parent. + * + * @return the current parent. + */ + @FxThread + protected @Nullable Object getCurrentParent() { + return currentParent; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilder.java similarity index 82% rename from src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilder.java index 0e72627e..5058c8b4 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilder.java @@ -1,7 +1,9 @@ -package com.ss.editor.ui.control.property.builder; +package com.ss.builder.fx.control.property.builder; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderFilter.java b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderFilter.java similarity index 79% rename from src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderFilter.java rename to src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderFilter.java index 7c7d2cb0..a3410c61 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderFilter.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderFilter.java @@ -1,5 +1,7 @@ -package com.ss.editor.ui.control.property.builder; +package com.ss.builder.fx.control.property.builder; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,5 +21,6 @@ public interface PropertyBuilderFilter { * @param parent the parent. * @return true of we should skip the builder for the object. */ + @FxThread boolean skip(@NotNull PropertyBuilder builder, @NotNull Object object, @Nullable Object parent); } diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderRegistry.java b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderRegistry.java new file mode 100644 index 00000000..0d444025 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/PropertyBuilderRegistry.java @@ -0,0 +1,112 @@ +package com.ss.builder.fx.control.property.builder; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.builder.impl.*; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.control.property.builder.impl.*; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The factory to build property controls for an object. + * + * @author JavaSaBr + */ +public class PropertyBuilderRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(PropertyBuilderRegistry.class); + + /** + * @see PropertyBuilder + */ + public static final String EP_BUILDERS = "PropertyBuilderRegistry#builders"; + + /** + * @see PropertyBuilderFilter + */ + public static final String EP_FILTERS = "PropertyBuilderRegistry#filters"; + + private static final ExtensionPoint PROPERTY_BUILDERS = + ExtensionPointManager.register(EP_BUILDERS); + + private static final ExtensionPoint PROPERTY_BUILDER_FILTERS = + ExtensionPointManager.register(EP_FILTERS); + + private static final PropertyBuilderRegistry INSTANCE = new PropertyBuilderRegistry(); + + @FromAnyThread + public static @NotNull PropertyBuilderRegistry getInstance() { + return INSTANCE; + } + + private PropertyBuilderRegistry() { + + PROPERTY_BUILDERS.register(AudioNodePropertyBuilder.getInstance()) + .register(ParticleEmitterPropertyBuilder.getInstance()) + .register(GeometryPropertyBuilder.getInstance()) + .register(LightPropertyBuilder.getInstance()) + .register(SpatialPropertyBuilder.getInstance()) + .register(SceneAppStatePropertyBuilder.getInstance()) + .register(SceneFilterPropertyBuilder.getInstance()) + .register(DefaultControlPropertyBuilder.getInstance()) + .register(EditableControlPropertyBuilder.getInstance()) + .register(CollisionShapePropertyBuilder.getInstance()) + .register(PrimitivePropertyBuilder.getInstance()) + .register(MeshPropertyBuilder.getInstance()) + .register(MaterialPropertyBuilder.getInstance()) + .register(ParticleInfluencerPropertyBuilder.getInstance()) + .register(EmitterShapePropertyBuilder.getInstance()) + .register(MaterialSettingsPropertyBuilder.getInstance()); + + LOGGER.info("initialized."); + } + + /** + * Build properties controls for the object to the container. + * + * @param object the object to build property controls. + * @param parent the parent of the object. + * @param container the container for containing these controls. + * @param changeConsumer the consumer to work between controls and editor. + */ + @FxThread + public void buildFor( + @NotNull Object object, + @Nullable Object parent, + @NotNull VBox container, + @NotNull ChangeConsumer changeConsumer + ) { + + var filters = PROPERTY_BUILDER_FILTERS.getExtensions(); + + for (var builder : PROPERTY_BUILDERS.getExtensions()) { + + boolean needSkip = false; + + for (var filter : filters) { + if (filter.skip(builder, object, parent)) { + needSkip = true; + break; + } + } + + if (needSkip) { + continue; + } + + builder.buildFor(object, parent, container, changeConsumer); + } + + PropertyControl.constructProperties(container); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/AbstractPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/AbstractPropertyBuilder.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/AbstractPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/AbstractPropertyBuilder.java index abe83444..9f9266b8 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/AbstractPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/AbstractPropertyBuilder.java @@ -1,9 +1,12 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FxUtils; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; @@ -71,8 +74,7 @@ protected void buildSplitLine(@NotNull Pane pane) { var container = new VBox(line); FxUtils.addClass(line, CssClasses.DEF_HBOX) - .addClass(container, - CssClasses.PROPERTY_EDITOR_CONTAINER_SPLIT_LINE); + .addClass(container, CssClasses.PROPERTY_EDITOR_CONTAINER_SPLIT_LINE); FxUtils.addChild(pane, container); } diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/AudioNodePropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/AudioNodePropertyBuilder.java new file mode 100644 index 00000000..2ae0c0f8 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/AudioNodePropertyBuilder.java @@ -0,0 +1,98 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.jme3.audio.AudioKey; +import com.jme3.audio.AudioNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.util.AudioNodeUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.property.*; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import com.ss.builder.util.AudioNodeUtils; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +import static com.ss.editor.extension.property.EditablePropertyType.*; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link AudioNode} objects. + * + * @author JavaSaBr + */ +public class AudioNodePropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final Setter AUDIO_APPLY_HANDLER = (audioNode, audioKey) -> { + + var assetManager = EditorUtils.getAssetManager(); + + if (audioKey == null) { + AudioNodeUtils.updateData(audioNode, null, null); + } else { + AudioNodeUtils.updateData(audioNode, assetManager.loadAudio(audioKey), audioKey); + } + }; + + private static final PropertyBuilder INSTANCE = new AudioNodePropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private AudioNodePropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!(object instanceof AudioNode)) { + return null; + } + + var audioNode = (AudioNode) object; + var properties = new ArrayList>(); + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_LOOPING, audioNode, + AudioNode::isLooping, AudioNode::setLooping)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_REVERB, audioNode, + AudioNode::isReverbEnabled, AudioNode::setReverbEnabled)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_DIRECTIONAL, audioNode, + AudioNode::isDirectional, AudioNode::setDirectional)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_DIRECTIONAL, audioNode, + AudioNode::isPositional, AudioNode::setPositional)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_AUDIO_PITCH, 2F, 0.5F, 2F, audioNode, + AudioNode::getPitch, AudioNode::setPitch)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_AUDIO_VOLUME, 5F, 0F, Integer.MAX_VALUE, audioNode, + AudioNode::getVolume, AudioNode::setVolume)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_TIME_OFFSET, 1F, 0F, Integer.MAX_VALUE, audioNode, + AudioNode::getTimeOffset, AudioNode::setTimeOffset)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_DISTANCE, 1F, 0F, Integer.MAX_VALUE, audioNode, + AudioNode::getMaxDistance, AudioNode::setMaxDistance)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_REF_DISTANCE, 1F, 0F, Integer.MAX_VALUE, audioNode, + AudioNode::getRefDistance, AudioNode::setRefDistance)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_INNER_ANGLE, audioNode, + AudioNode::getInnerAngle, AudioNode::setInnerAngle)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_OUTER_ANGLE, audioNode, + AudioNode::getOuterAngle, AudioNode::setOuterAngle)); + + properties.add(SeparatorProperty.getInstance()); + + properties.add(new SimpleProperty<>(AUDIO_KEY, Messages.MODEL_PROPERTY_AUDIO_DATA, audioNode, + AudioNodeUtils::getAudioKey, AUDIO_APPLY_HANDLER)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_VELOCITY, audioNode, + AudioNode::getVelocity, AudioNode::setVelocity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, audioNode, + AudioNode::getDirection, AudioNode::setDirection)); + + return properties; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/CollisionShapePropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/CollisionShapePropertyBuilder.java new file mode 100644 index 00000000..54f702c1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/CollisionShapePropertyBuilder.java @@ -0,0 +1,127 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import static com.ss.editor.extension.property.EditablePropertyType.READ_ONLY_STRING; +import com.jme3.bullet.collision.shapes.*; +import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; +import com.jme3.math.Matrix3f; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import com.ss.builder.fx.control.property.impl.DefaultSinglePropertyControl; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FXUtils; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link CollisionShape} objects. + * + * @author JavaSaBr + */ +public class CollisionShapePropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final Array> SUPPORTED_TYPES = Array.of( + ChildCollisionShape.class, + CollisionShape.class + ); + + private static final PropertyBuilder INSTANCE = new CollisionShapePropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private CollisionShapePropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!SUPPORTED_TYPES.anyMatch(object, Class::isInstance)) { + return null; + } + + var properties = new ArrayList>(); + + if (object instanceof ChildCollisionShape) { + + var shape = (ChildCollisionShape) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_LOCATION, shape, + collisionShape -> String.valueOf(collisionShape.location))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_ROTATION, shape, + collisionShape -> String.valueOf(new Quaternion().fromRotationMatrix(collisionShape.rotation)))); + } + + if (object instanceof BoxCollisionShape) { + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_HALF_EXTENTS, + (BoxCollisionShape) object, shape -> String.valueOf(shape.getHalfExtents()))); + + } else if (object instanceof SphereCollisionShape) { + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_RADIUS, + (SphereCollisionShape) object, shape -> String.valueOf(shape.getRadius()))); + + } else if (object instanceof CapsuleCollisionShape) { + + var shape = (CapsuleCollisionShape) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_RADIUS, shape, + collisionShape -> String.valueOf(collisionShape.getRadius()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_HEIGHT, shape, + collisionShape -> String.valueOf(collisionShape.getHeight()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_AXIS, shape, + collisionShape -> String.valueOf(collisionShape.getAxis()))); + + } else if (object instanceof ConeCollisionShape) { + + var shape = (ConeCollisionShape) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_RADIUS, shape, + collisionShape -> String.valueOf(collisionShape.getRadius()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_HEIGHT, shape, + collisionShape -> String.valueOf(collisionShape.getHeight()))); + + } else if (object instanceof CylinderCollisionShape) { + + var shape = (CylinderCollisionShape) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_HALF_EXTENTS, shape, + collisionShape -> String.valueOf(collisionShape.getHalfExtents()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_AXIS, shape, + collisionShape -> String.valueOf(collisionShape.getAxis()))); + } + + if (object instanceof CollisionShape) { + + var shape = (CollisionShape) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_SCALE, shape, + collisionShape -> String.valueOf(collisionShape.getScale()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_OBJECT_ID, shape, + collisionShape -> String.valueOf(collisionShape.getObjectId()))); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_MARGIN, shape, + collisionShape -> String.valueOf(collisionShape.getMargin()))); + } + + return properties; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/DefaultControlPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/DefaultControlPropertyBuilder.java new file mode 100644 index 00000000..6b547840 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/DefaultControlPropertyBuilder.java @@ -0,0 +1,250 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import static com.ss.editor.extension.property.EditablePropertyType.*; +import com.jme3.animation.Animation; +import com.jme3.animation.SkeletonControl; +import com.jme3.bullet.control.BetterCharacterControl; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.cinematic.events.AbstractCinematicEvent; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.control.Control; +import com.jme3.scene.control.LightControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for default controls. + * + * @author JavaSaBr + */ +public class DefaultControlPropertyBuilder extends EditableModelObjectPropertyBuilder { + + public static final int PRIORITY = 0; + + private static final PropertyBuilder INSTANCE = new DefaultControlPropertyBuilder(); + + @FxThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private DefaultControlPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @FxThread + protected @NotNull List> getProperties(@NotNull AbstractControl control) { + + var result = new ArrayList>(); + result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, + AbstractControl::isEnabled, AbstractControl::setEnabled)); + + return result; + } + + @FxThread + protected @NotNull List> getProperties(@NotNull PhysicsControl control) { + + var result = new ArrayList>(); + result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, + PhysicsControl::isEnabled, PhysicsControl::setEnabled)); + + return result; + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + var properties = new ArrayList>(); + + if (object instanceof VehicleWheel) { + + var control = (VehicleWheel) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_FRONT, control, + VehicleWheel::isFrontWheel, VehicleWheel::setFrontWheel)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, + VehicleWheel::isApplyLocal, VehicleWheel::setApplyLocal)); + properties.add(new SimpleProperty<>(STRING, Messages.MODEL_PROPERTY_OBJECT_ID, control, + wheel -> String.valueOf(wheel.getWheelId()))); + + properties.add(new SimpleProperty<>(SPATIAL_FROM_SCENE, Messages.MODEL_PROPERTY_WHEEL_SPATIAL, control, + VehicleWheel::getWheelSpatial, VehicleWheel::setWheelSpatial)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LOCATION, control, + VehicleWheel::getLocation)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, + VehicleWheel::getDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_AXLE, control, + VehicleWheel::getAxle)); + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_COMPRESSION, control, + VehicleWheel::getWheelsDampingCompression, VehicleWheel::setWheelsDampingCompression)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION_SLIP, control, + VehicleWheel::getFrictionSlip, VehicleWheel::setFrictionSlip)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, control, + VehicleWheel::getRadius, VehicleWheel::setRadius)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_FORCE, control, + VehicleWheel::getMaxSuspensionForce, VehicleWheel::setMaxSuspensionForce)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, + VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, + VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_RELAXATION, control, + VehicleWheel::getWheelsDampingRelaxation, VehicleWheel::setWheelsDampingRelaxation)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SUSPENSION_STIFFNESS, control, + VehicleWheel::getSuspensionStiffness, VehicleWheel::setSuspensionStiffness)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_REST_LENGTH, control, + VehicleWheel::getRestLength, VehicleWheel::setRestLength)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ROLL_INFLUENCE, control, + VehicleWheel::getRollInfluence, VehicleWheel::setRollInfluence)); + + } else if (object instanceof AbstractCinematicEvent) { + + var control = (AbstractCinematicEvent) object; + + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_LOOP_MODE, control, + AbstractCinematicEvent::getLoopMode, AbstractCinematicEvent::setLoopMode)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_INITIAL_DURATION, control, + AbstractCinematicEvent::getInitialDuration, AbstractCinematicEvent::setInitialDuration)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SPEED, control, + AbstractCinematicEvent::getSpeed, AbstractCinematicEvent::setSpeed)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_TIME, control, + AbstractCinematicEvent::getTime, AbstractCinematicEvent::setTime)); + + } else if (object instanceof Animation) { + + var animation = (Animation) object; + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LENGTH, animation, + Animation::getLength)); + } + + if (object instanceof MotionEvent) { + + var control = (MotionEvent) object; + + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, + MotionEvent::getDirectionType, MotionEvent::setDirectionType)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, + MotionEvent::getDirection, MotionEvent::setDirection)); + properties.add(new SimpleProperty<>(QUATERNION, Messages.MODEL_PROPERTY_ROTATION, control, + MotionEvent::getRotation, MotionEvent::setRotation)); + } + + if (!(object instanceof Control)) { + return properties; + } + + if (object instanceof AbstractControl) { + properties.addAll(getProperties((AbstractControl) object)); + } + + if (object instanceof PhysicsControl) { + properties.addAll(getProperties((PhysicsControl) object)); + } + + if (object instanceof LightControl) { + + var control = (LightControl) object; + + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, + LightControl::getControlDir, LightControl::setControlDir)); + properties.add(new SimpleProperty<>(LIGHT_FROM_SCENE, Messages.MODEL_PROPERTY_LIGHT, control, + LightControl::getLight, LightControl::setLight)); + + } else if (object instanceof BetterCharacterControl) { + + var control = (BetterCharacterControl) object; + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + BetterCharacterControl::getGravity, BetterCharacterControl::setGravity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_VELOCITY, control, + BetterCharacterControl::getVelocity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + BetterCharacterControl::getViewDirection, BetterCharacterControl::setViewDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, + BetterCharacterControl::getWalkDirection, BetterCharacterControl::setWalkDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_JUMP_FORCE, control, + BetterCharacterControl::getJumpForce, BetterCharacterControl::setJumpForce)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, + BetterCharacterControl::getDuckedFactor, BetterCharacterControl::setDuckedFactor)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_PHYSICS_DAMPING, control, + BetterCharacterControl::getPhysicsDamping, BetterCharacterControl::setPhysicsDamping)); + + } else if (object instanceof RigidBodyControl) { + + var control = (RigidBodyControl) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC_SPATIAL, control, + RigidBodyControl::isKinematicSpatial, RigidBodyControl::setKinematicSpatial)); + + } else if (object instanceof SkeletonControl) { + + var control = (SkeletonControl) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_HARDWARE_SKINNING_PREFERRED, control, + SkeletonControl::isHardwareSkinningPreferred, SkeletonControl::setHardwareSkinningPreferred)); + + } else if (object instanceof VehicleControl) { + + var control = (VehicleControl) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, + VehicleControl::isApplyPhysicsLocal, VehicleControl::setApplyPhysicsLocal)); + + } + + if (object instanceof PhysicsRigidBody) { + + var control = (PhysicsRigidBody) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC, control, + PhysicsRigidBody::isKinematic, PhysicsRigidBody::setKinematic)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + PhysicsRigidBody::getGravity, PhysicsRigidBody::setGravity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LINEAR_FACTOR, control, + PhysicsRigidBody::getLinearFactor, PhysicsRigidBody::setLinearFactor)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_ANGULAR_VELOCITY, control, + PhysicsRigidBody::getAngularVelocity, PhysicsRigidBody::setAngularVelocity)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_DAMPING, control, + PhysicsRigidBody::getAngularDamping, PhysicsRigidBody::setAngularDamping)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_FACTOR, control, + PhysicsRigidBody::getAngularFactor, PhysicsRigidBody::setAngularFactor)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_SLEEPING_THRESHOLD, control, + PhysicsRigidBody::getAngularSleepingThreshold, PhysicsRigidBody::setAngularSleepingThreshold)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION, control, + PhysicsRigidBody::getFriction, PhysicsRigidBody::setFriction)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MASS, control, + PhysicsRigidBody::getMass, PhysicsRigidBody::setMass)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LINEAR_DAMPING, control, + PhysicsRigidBody::getLinearDamping, PhysicsRigidBody::setLinearDamping)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RESTITUTION, control, + PhysicsRigidBody::getRestitution, PhysicsRigidBody::setRestitution)); + } + + return properties; + } + + @Override + public int getPriority() { + return PRIORITY; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableControlPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableControlPropertyBuilder.java new file mode 100644 index 00000000..6710c108 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableControlPropertyBuilder.java @@ -0,0 +1,43 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.control.EditableControl; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The property builder to build property controls of editable controls. + * + * @author JavaSaBr + */ +public class EditableControlPropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final EditableControlPropertyBuilder INSTANCE = new EditableControlPropertyBuilder(); + + @FromAnyThread + public static @NotNull EditableControlPropertyBuilder getInstance() { + return INSTANCE; + } + + private EditableControlPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + if (object instanceof EditableControl) { + return ((EditableControl) object).getEditableProperties(); + } else { + return null; + } + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableModelObjectPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableModelObjectPropertyBuilder.java similarity index 75% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableModelObjectPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableModelObjectPropertyBuilder.java index 5eb2d1ef..66bd5cea 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableModelObjectPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableModelObjectPropertyBuilder.java @@ -1,5 +1,6 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; +import com.jme3.audio.AudioKey; import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; import com.jme3.light.Light; @@ -8,12 +9,15 @@ import com.jme3.post.Filter; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.property.EditableProperty; import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.control.property.impl.*; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.control.property.impl.*; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; @@ -47,7 +51,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new LightElementModelPropertyControl>( - DirectionalLight.class, value, property.getName(), changeConsumer); + DirectionalLight.class, value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -58,7 +62,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new LightElementModelPropertyControl>( - AmbientLight.class, value, property.getName(), changeConsumer); + AmbientLight.class, value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -69,7 +73,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new LightElementModelPropertyControl>( - PointLight.class, value, property.getName(), changeConsumer); + PointLight.class, value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -80,7 +84,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new LightElementModelPropertyControl>( - Light.class, value, property.getName(), changeConsumer); + Light.class, value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -91,7 +95,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new SpatialElementModelPropertyControl>( - Spatial.class, value, property.getName(), changeConsumer); + Spatial.class, value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -102,7 +106,18 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new SpatialElementModelPropertyControl>( - Node.class, value, property.getName(), changeConsumer); + Node.class, value, property.getName(), changeConsumer); + + addControl(container, property, propertyControl); + break; + } + case AUDIO_KEY: { + + EditableProperty property = cast(description); + + var value = property.getValue(); + var propertyControl = new AudioKeyPropertyControl>( + value, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -122,7 +137,7 @@ protected void buildFor( var value = property.getValue(); var propertyControl = new FilterElementModelPropertyControl>( - value, property.getName(), consumer); + value, property.getName(), consumer); addControl(container, property, propertyControl); break; diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableObjectPropertyBuilder.java similarity index 94% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableObjectPropertyBuilder.java index b2fe1993..504de459 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EditableObjectPropertyBuilder.java @@ -1,15 +1,17 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.math.*; import com.jme3.texture.Texture2D; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.control.property.impl.*; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.control.property.impl.*; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.util.ClassUtils; import com.ss.rlib.fx.util.FxUtils; import javafx.scene.layout.VBox; @@ -40,6 +42,7 @@ protected void buildForImpl( ) { var properties = getProperties(object, parent, changeConsumer); + if (properties == null || properties.isEmpty()) { return; } @@ -192,7 +195,7 @@ protected void buildFor( var currentValue = property.getValue(); var propertyControl = new QuaternionPropertyControl>( - currentValue, property.getName(), changeConsumer); + currentValue, property.getName(), changeConsumer); addControl(container, property, propertyControl); break; @@ -201,7 +204,7 @@ protected void buildFor( EditableProperty, ?> property = cast(description); var value = notNull(property.getValue(), "Enum value can't be null."); - var availableValues = EditorUtil.getAvailableValues(value); + var availableValues = EditorUtils.getAvailableValues(value); var propertyControl = new EnumPropertyControl, ?>, Enum>(value, property.getName(), changeConsumer, availableValues); diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/EmitterShapePropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EmitterShapePropertyBuilder.java new file mode 100644 index 00000000..636d977e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/EmitterShapePropertyBuilder.java @@ -0,0 +1,81 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; +import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; +import com.jme3.effect.shapes.EmitterBoxShape; +import com.jme3.effect.shapes.EmitterPointShape; +import com.jme3.effect.shapes.EmitterShape; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SeparatorProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link EmitterShape}. + * + * @author JavaSaBr + */ +public class EmitterShapePropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final PropertyBuilder INSTANCE = new EmitterShapePropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private EmitterShapePropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!(object instanceof EmitterShape)) { + return null; + } + + var shape = (EmitterShape) object; + var properties = new ArrayList>(); + + if (shape instanceof EmitterPointShape) { + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_POINT, (EmitterPointShape) shape, + EmitterPointShape::getPoint, EmitterPointShape::setPoint)); + + } else if (shape instanceof EmitterBoxShape) { + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LENGTH, (EmitterBoxShape) shape, + EmitterBoxShape::getLen, EmitterBoxShape::setLen)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_MIN, (EmitterBoxShape) shape, + EmitterBoxShape::getMin, EmitterBoxShape::setMin)); + + } else if (shape instanceof EmitterSphereShape) { + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, (EmitterSphereShape) shape, + EmitterSphereShape::getRadius, EmitterSphereShape::setRadius)); + + properties.add(SeparatorProperty.getInstance()); + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_CENTER, (EmitterSphereShape) shape, + EmitterSphereShape::getCenter, EmitterSphereShape::setCenter)); + } + + return properties; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/GeometryPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/GeometryPropertyBuilder.java new file mode 100644 index 00000000..a9d246c0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/GeometryPropertyBuilder.java @@ -0,0 +1,178 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.jme3.asset.MaterialKey; +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; +import com.jme3.bounding.BoundingVolume; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import com.ss.builder.fx.control.property.impl.DefaultPropertyControl; +import com.ss.builder.fx.control.property.impl.LodLevelPropertyControl; +import com.ss.builder.fx.control.property.impl.MaterialKeyPropertyControl; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.ExtMath; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link Geometry} objects. + * + * @author JavaSaBr + */ +public class GeometryPropertyBuilder extends AbstractPropertyBuilder { + + @FunctionalInterface + public interface CanEditMaterialChecker { + + @FxThread + boolean canEdit(@NotNull Geometry geometry); + } + + /** + * @see CanEditMaterialChecker + */ + public static final String EP_CAN_EDIT_MATERIAL_CHECKERS = "GeometryPropertyBuilder#canEditMaterialCheckers"; + + private static final ExtensionPoint CAN_EDIT_MATERIAL_CHECKERS = + ExtensionPointManager.register(EP_CAN_EDIT_MATERIAL_CHECKERS); + + private static final BiConsumer MATERIAL_APPLY_HANDLER = (geometry, materialKey) -> { + + var assetManager = EditorUtils.getAssetManager(); + + if (materialKey == null) { + + var material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor("Color", ColorRGBA.Gray); + + geometry.setMaterial(material); + + } else { + var material = assetManager.loadAsset(materialKey); + geometry.setMaterial(material); + } + }; + + private static final Function MATERIAL_SYNC_HANDLER = + geometry -> (MaterialKey) geometry + .getMaterial() + .getKey(); + + private static final Function BOUNDING_VOLUME_TO_STRING = boundingVolume -> { + + if (boundingVolume instanceof BoundingSphere) { + + var sphere = Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_SPHERE; + var radius = Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_SPHERE_RADIUS; + var boundingSphere = (BoundingSphere) boundingVolume; + + return sphere + ": [" + radius + "=" + boundingSphere.getRadius() + "]"; + + } else if (boundingVolume instanceof BoundingBox) { + + var box = Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_BOX; + var boundingBox = (BoundingBox) boundingVolume; + var xExtent = ExtMath.cut(boundingBox.getXExtent(), 100); + var yExtent = ExtMath.cut(boundingBox.getYExtent(), 100); + var zExtent = ExtMath.cut(boundingBox.getZExtent(), 100); + + return box + ": [x=" + xExtent + ", y=" + yExtent + ", z=" + zExtent + "]"; + } + + return StringUtils.EMPTY; + }; + + private static final PropertyBuilder INSTANCE = new GeometryPropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private GeometryPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected void buildForImpl( + @NotNull Object object, + @Nullable Object parent, + @NotNull VBox container, + @NotNull ModelChangeConsumer changeConsumer + ) { + + if (!(object instanceof Geometry)) { + return; + } + + var geometry = (Geometry) object; + var modelBound = geometry.getModelBound(); + var lodLevel = geometry.getLodLevel(); + + var boundingVolumeControl = new DefaultPropertyControl( + modelBound, Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_NAME, changeConsumer); + + boundingVolumeControl.setToStringFunction(BOUNDING_VOLUME_TO_STRING); + boundingVolumeControl.reload(); + boundingVolumeControl.setEditObject(geometry); + + if (canEditMaterial(geometry)) { + + var material = geometry.getMaterial(); + var materialKey = (MaterialKey) material.getKey(); + + var materialControl = new MaterialKeyPropertyControl(materialKey, + Messages.MODEL_PROPERTY_MATERIAL, changeConsumer); + + materialControl.setApplyHandler(MATERIAL_APPLY_HANDLER); + materialControl.setSyncHandler(MATERIAL_SYNC_HANDLER); + materialControl.setEditObject(geometry); + + FxUtils.addChild(container, materialControl); + } + + FxUtils.addChild(container, boundingVolumeControl); + + buildSplitLine(container); + + final LodLevelPropertyControl lodLevelControl = + new LodLevelPropertyControl<>(lodLevel, Messages.MODEL_PROPERTY_LOD, changeConsumer); + + lodLevelControl.setApplyHandler(Geometry::setLodLevel); + lodLevelControl.setSyncHandler(Geometry::getLodLevel); + lodLevelControl.setEditObject(geometry, true); + + FxUtils.addChild(container, lodLevelControl); + } + + /** + * Can edit material boolean. + * + * @param geometry the geometry. + * @return true if we can editor the material. + */ + @FromAnyThread + private boolean canEditMaterial(@NotNull Geometry geometry) { + return CAN_EDIT_MATERIAL_CHECKERS.anyMatchNot(geometry, CanEditMaterialChecker::canEdit); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/LightPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/LightPropertyBuilder.java new file mode 100644 index 00000000..f0ecdfa5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/LightPropertyBuilder.java @@ -0,0 +1,99 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import static com.ss.editor.extension.property.EditablePropertyType.*; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.math.FastMath; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SeparatorProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link Light} objects. + * + * @author JavaSaBr + */ +public class LightPropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final PropertyBuilder INSTANCE = new LightPropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private LightPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!(object instanceof Light)) { + return null; + } + + var light = (Light) object; + var properties = new ArrayList>(); + + if (light instanceof DirectionalLight) { + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, (DirectionalLight) light, + DirectionalLight::getDirection, DirectionalLight::setDirection)); + + properties.add(SeparatorProperty.getInstance()); + + } else if (light instanceof SpotLight) { + + var spotLight = (SpotLight) light; + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, spotLight, + SpotLight::getDirection, SpotLight::setDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LOCATION, spotLight, + SpotLight::getPosition, SpotLight::setPosition)); + + properties.add(SeparatorProperty.getInstance()); + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, 1F, 0F, Integer.MAX_VALUE, spotLight, + SpotLight::getSpotRange, SpotLight::setSpotRange)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_INNER_ANGLE, 1F, 0F, FastMath.HALF_PI, spotLight, + SpotLight::getSpotInnerAngle, SpotLight::setSpotInnerAngle)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_OUTER_ANGLE, 1F, 0F, FastMath.HALF_PI, spotLight, + SpotLight::getSpotOuterAngle, SpotLight::setSpotOuterAngle)); + + } else if (light instanceof PointLight) { + + var pointLight = (PointLight) light; + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LOCATION, pointLight, + PointLight::getPosition, PointLight::setPosition)); + + properties.add(SeparatorProperty.getInstance()); + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, 1F, 0F, Integer.MAX_VALUE, pointLight, + PointLight::getRadius, PointLight::setRadius)); + } + + properties.add(new SimpleProperty<>(COLOR, Messages.MODEL_PROPERTY_COLOR, light, + Light::getColor, Light::setColor)); + + return properties; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialPropertyBuilder.java similarity index 87% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialPropertyBuilder.java index 8749d25d..2c6ab8a1 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialPropertyBuilder.java @@ -1,26 +1,28 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; import static java.util.stream.Collectors.toList; import com.jme3.material.MatParam; import com.jme3.material.Material; -import com.jme3.material.MaterialDef; import com.jme3.shader.VarType; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.property.EditableProperty; import com.ss.editor.extension.property.EditablePropertyType; import com.ss.editor.extension.property.SimpleProperty; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; import com.ss.rlib.common.util.dictionary.DictionaryFactory; import com.ss.rlib.common.util.dictionary.ObjectDictionary; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * The implementation of the {@link PropertyBuilder} to build property controls for {@link com.jme3.material.Material} objects. @@ -29,10 +31,6 @@ */ public class MaterialPropertyBuilder extends EditableObjectPropertyBuilder { - @NotNull - private static final PropertyBuilder INSTANCE = new MaterialPropertyBuilder(); - - @NotNull private static final ObjectDictionary SIZE_MAP = DictionaryFactory.newObjectDictionary(); static { @@ -43,18 +41,14 @@ public class MaterialPropertyBuilder extends EditableObjectPropertyBuilder { SIZE_MAP.put(VarType.Int, 2); } - @NotNull protected static final Comparator MAT_PARAM_COMPARATOR = (first, second) -> { var firstType = first.getVarType(); var secondType = second.getVarType(); return SIZE_MAP.get(secondType, () -> 0) - SIZE_MAP.get(firstType, () -> 0); }; - /** - * Get the single instance. - * - * @return the single instance - */ + private static final PropertyBuilder INSTANCE = new MaterialPropertyBuilder(); + @FromAnyThread public static @NotNull PropertyBuilder getInstance() { return INSTANCE; @@ -68,7 +62,7 @@ protected MaterialPropertyBuilder() { @FxThread protected @Nullable List> getProperties(@NotNull Object object) { - if(!(object instanceof Material)) { + if (!(object instanceof Material)) { return null; } @@ -93,6 +87,7 @@ protected MaterialPropertyBuilder() { private @Nullable EditableProperty convert(@NotNull MatParam param, @NotNull Material material) { var propertyType = convert(param.getVarType()); + if (propertyType == null) { return null; } @@ -110,7 +105,6 @@ protected MaterialPropertyBuilder() { */ @FxThread protected void applyParam(@NotNull MatParam param, @NotNull Material material, @Nullable Object newValue) { - if (newValue == null) { material.clearParam(param.getName()); } else { @@ -127,8 +121,9 @@ protected void applyParam(@NotNull MatParam param, @NotNull Material material, @ */ @FxThread protected @Nullable Object getParamValue(@NotNull MatParam param, @NotNull Material material) { - var currentParam = material.getParam(param.getName()); - return currentParam == null ? null : currentParam.getValue(); + return Optional.ofNullable(material.getParam(param.getName())) + .map(MatParam::getValue) + .orElse(null); } /** diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialSettingsPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialSettingsPropertyBuilder.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialSettingsPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialSettingsPropertyBuilder.java index 24d5e442..13c929e3 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialSettingsPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MaterialSettingsPropertyBuilder.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; import static com.ss.editor.extension.property.EditablePropertyType.*; import com.jme3.material.MatParam; @@ -6,14 +6,18 @@ import com.jme3.material.MaterialDef; import com.jme3.material.RenderState; import com.jme3.shader.VarType; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.*; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.EditableProperty; import com.ss.editor.extension.property.EditablePropertyType; import com.ss.editor.extension.property.SimpleProperty; -import com.ss.editor.model.node.material.*; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; +import com.ss.builder.model.node.material.*; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; import com.ss.rlib.common.util.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,7 +32,6 @@ */ public class MaterialSettingsPropertyBuilder extends MaterialPropertyBuilder { - @NotNull private static final Comparator MAT_PARAM_NAME_COMPARATOR = (first, second) -> { int result = MAT_PARAM_COMPARATOR.compare(first, second); @@ -40,22 +43,16 @@ public class MaterialSettingsPropertyBuilder extends MaterialPropertyBuilder { return StringUtils.compareIgnoreCase(first.getName(), second.getName()); }; - @NotNull - private static final Set TEXTURE_TYPES = new HashSet<>(); + private static final Set TEXTURE_TYPES = Set.of( + VarType.Texture2D, + VarType.TextureCubeMap, + VarType.Texture3D, + VarType.TextureArray, + VarType.TextureBuffer + ); - @NotNull - private static final Set COLOR_TYPES = new HashSet<>(); + private static final Set COLOR_TYPES = Set.of(VarType.Vector4); - static { - TEXTURE_TYPES.add(VarType.Texture2D); - TEXTURE_TYPES.add(VarType.TextureCubeMap); - TEXTURE_TYPES.add(VarType.Texture3D); - TEXTURE_TYPES.add(VarType.TextureArray); - TEXTURE_TYPES.add(VarType.TextureBuffer); - COLOR_TYPES.add(VarType.Vector4); - } - - @NotNull private static final PropertyBuilder INSTANCE = new MaterialSettingsPropertyBuilder(); @FromAnyThread @@ -65,20 +62,20 @@ public class MaterialSettingsPropertyBuilder extends MaterialPropertyBuilder { @Override @FxThread - protected @Nullable List> getProperties(@NotNull final Object object) { + protected @Nullable List> getProperties(@NotNull Object object) { if (!(object instanceof MaterialSettings) || object instanceof RootMaterialSettings) { return null; } - final MaterialSettings settings = (MaterialSettings) object; - final Material material = settings.getMaterial(); + var settings = (MaterialSettings) object; + var material = settings.getMaterial(); if(object instanceof RenderSettings) { - final RenderState renderState = material.getAdditionalRenderState(); + var renderState = material.getAdditionalRenderState(); - final List> result = new ArrayList<>(); + var result = new ArrayList>(); result.add(new SimpleProperty<>(BOOLEAN, Messages.MATERIAL_RENDER_STATE_COLOR_WRITE, settings, sett -> renderState.isColorWrite(), (sett, property) -> renderState.setColorWrite(property))); @@ -113,9 +110,8 @@ public class MaterialSettingsPropertyBuilder extends MaterialPropertyBuilder { return result; } - final MaterialDef materialDef = material.getMaterialDef(); - - return materialDef.getMaterialParams() + return material.getMaterialDef() + .getMaterialParams() .stream() .filter(param -> filter(param, object)) .sorted(MAT_PARAM_NAME_COMPARATOR) @@ -132,7 +128,7 @@ public class MaterialSettingsPropertyBuilder extends MaterialPropertyBuilder { * @return true of we can show the parameter. */ @FxThread - private boolean filter(@NotNull final MatParam param, @NotNull final Object object) { + private boolean filter(@NotNull MatParam param, @NotNull Object object) { if (object instanceof TexturesSettings) { return TEXTURE_TYPES.contains(param.getVarType()); @@ -152,10 +148,13 @@ private boolean filter(@NotNull final MatParam param, @NotNull final Object obje * @return the editable property or null. */ @FxThread - private @Nullable EditableProperty convert(@NotNull final MatParam param, @NotNull final Material material, - @NotNull final MaterialSettings settings) { + private @Nullable EditableProperty convert( + @NotNull MatParam param, + @NotNull Material material, + @NotNull MaterialSettings settings + ) { - final EditablePropertyType propertyType = convert(param.getVarType()); + var propertyType = convert(param.getVarType()); if (propertyType == null) { return null; } diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/MeshPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MeshPropertyBuilder.java new file mode 100644 index 00000000..eafd488e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/MeshPropertyBuilder.java @@ -0,0 +1,70 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.jme3.scene.Mesh; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +import static com.ss.editor.extension.property.EditablePropertyType.ENUM; +import static com.ss.editor.extension.property.EditablePropertyType.READ_ONLY_STRING; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link Mesh} objects. + * + * @author JavaSaBr + */ +public class MeshPropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final PropertyBuilder INSTANCE = new MeshPropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private MeshPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!(object instanceof Mesh)) { + return null; + } + + var mesh = (Mesh) object; + var properties = new ArrayList>(); + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_ID, mesh, + Mesh::getId)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_INSTANCE_COUNT, mesh, + Mesh::getInstanceCount)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_INSTANCE_COUNT, mesh, + Mesh::getInstanceCount)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_VERTEX_COUNT, mesh, + Mesh::getVertexCount)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_TRIANGLE_COUNT, mesh, + Mesh::getTriangleCount)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_NUM_LOD_LEVELS, mesh, + Mesh::getNumLodLevels)); + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_MODE, mesh, + Mesh::getMode, Mesh::setMode)); + + return properties; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleEmitterPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleEmitterPropertyBuilder.java similarity index 93% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleEmitterPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleEmitterPropertyBuilder.java index aac50438..b215c323 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleEmitterPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleEmitterPropertyBuilder.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; import static com.ss.editor.extension.property.EditablePropertyType.*; import static com.ss.rlib.common.util.ObjectUtils.ifNull; @@ -6,11 +6,14 @@ import com.jme3.effect.ParticleEmitter; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.*; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,10 +50,12 @@ default void set(@NotNull ParticleEmitter emitter, @Nullable T value) { emitter.setStartSize(size.getX()); emitter.setEndSize(size.getY()); }; + private static final ChangeHandler LIFE_SETTER = (emitter, size) -> { emitter.setLowLife(size.getX()); emitter.setHighLife(size.getY()); }; + private static final ChangeHandler SPRITES_SETTER = (emitter, size) -> { emitter.setImagesX((int) size.getX()); emitter.setImagesY((int) size.getY()); diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java new file mode 100644 index 00000000..e7e62b4a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java @@ -0,0 +1,85 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import static com.ss.editor.extension.property.EditablePropertyType.*; +import com.jme3.effect.influencers.EmptyParticleInfluencer; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.jme3.effect.influencers.RadialParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SeparatorProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for {@link ParticleInfluencer}. + * + * @author JavaSaBr + */ +public class ParticleInfluencerPropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final PropertyBuilder INSTANCE = new ParticleInfluencerPropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private ParticleInfluencerPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + + if (!(object instanceof ParticleInfluencer)) { + return null; + } + + var influencer = (ParticleInfluencer) object; + var properties = new ArrayList>(); + + if (influencer instanceof EmptyParticleInfluencer) { + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_INITIAL_VELOCITY, + influencer.getInitialVelocity(), String::valueOf)); + } else { + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_INITIAL_VELOCITY, influencer, + ParticleInfluencer::getInitialVelocity, ParticleInfluencer::setInitialVelocity)); + } + + if (object instanceof RadialParticleInfluencer) { + + var radialParticleInfluencer = (RadialParticleInfluencer) object; + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_ORIGIN, radialParticleInfluencer, + RadialParticleInfluencer::getOrigin, RadialParticleInfluencer::setOrigin)); + + properties.add(SeparatorProperty.getInstance()); + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIAL_VELOCITY, radialParticleInfluencer, + RadialParticleInfluencer::getRadialVelocity, RadialParticleInfluencer::setRadialVelocity)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_HORIZONTAL, radialParticleInfluencer, + RadialParticleInfluencer::isHorizontal, RadialParticleInfluencer::setHorizontal)); + + } else { + properties.add(SeparatorProperty.getInstance()); + } + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_VELOCITY_VARIATION, influencer, + ParticleInfluencer::getVelocityVariation, ParticleInfluencer::setVelocityVariation)); + + return properties; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/PrimitivePropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/PrimitivePropertyBuilder.java new file mode 100644 index 00000000..845961f1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/PrimitivePropertyBuilder.java @@ -0,0 +1,116 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.property.SimpleProperty; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; +import com.ss.builder.fx.control.property.impl.DefaultSinglePropertyControl; +import com.ss.builder.fx.control.property.impl.Vector3fPropertyControl; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FXUtils; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.Buffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.ss.editor.extension.property.EditablePropertyType.ENUM; +import static com.ss.editor.extension.property.EditablePropertyType.READ_ONLY_STRING; +import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; + +/** + * The implementation of the {@link PropertyBuilder} to build property controls for primitive objects objects. + * + * @author JavaSaBr + */ +public class PrimitivePropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final Array> SUPPORTED_TYPES = Array.of( + Vector3f.class, + VertexBuffer.class, + Buffer.class + ); + + private static final PropertyBuilder INSTANCE = new PrimitivePropertyBuilder(); + + @FromAnyThread + public static @NotNull PropertyBuilder getInstance() { + return INSTANCE; + } + + private PrimitivePropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + protected @Nullable List> getProperties( + @NotNull Object object, + @Nullable Object parent, + @NotNull ModelChangeConsumer changeConsumer + ) { + + if (!SUPPORTED_TYPES.anyMatch(object, Class::isInstance)) { + return null; + } + + var properties = new ArrayList>(); + + if (object instanceof Vector3f) { + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_VALUE, (Vector3f) object, + Vector3f::clone, Vector3f::set)); + + } else if (object instanceof VertexBuffer) { + + var vertexBuffer = (VertexBuffer) object; + var data = vertexBuffer.getData(); + + if (data == null) { + return null; + } + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_TYPE, + vertexBuffer.getBufferType(), Enum::name)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_FORMAT, + vertexBuffer.getFormat(), Enum::name)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_USAGE, + vertexBuffer.getUsage(), Enum::name)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_UNIQ_ID, + vertexBuffer.getUniqueId(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_BASE_INSTANCE_COUNT, + vertexBuffer.getBaseInstanceCount(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_INSTANCE_SPAN, + vertexBuffer.getInstanceSpan(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_NUM_COMPONENTS, + vertexBuffer.getNumComponents(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_NUM_ELEMENTS, + vertexBuffer.getNumElements(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_OFFSET, + vertexBuffer.getOffset(), String::valueOf)); + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_STRIDE, + vertexBuffer.getStride(), String::valueOf)); + + } else if (object instanceof Buffer) { + + var buffer = (Buffer) object; + + properties.add(new SimpleProperty<>(READ_ONLY_STRING, Messages.MODEL_PROPERTY_CAPACITY, + buffer.capacity(), String::valueOf)); + } + + return properties; + } + +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneAppStatePropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneAppStatePropertyBuilder.java new file mode 100644 index 00000000..c51bea79 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneAppStatePropertyBuilder.java @@ -0,0 +1,43 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.app.state.EditableSceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The property builder to build property controls of editable scene app states. + * + * @author JavaSaBr + */ +public class SceneAppStatePropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final SceneAppStatePropertyBuilder INSTANCE = new SceneAppStatePropertyBuilder(); + + @FromAnyThread + public static @NotNull SceneAppStatePropertyBuilder getInstance() { + return INSTANCE; + } + + protected SceneAppStatePropertyBuilder() { + super(SceneChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + if (object instanceof EditableSceneAppState) { + return ((EditableSceneAppState) object).getEditableProperties(); + } else { + return null; + } + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneFilterPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneFilterPropertyBuilder.java new file mode 100644 index 00000000..37c588c9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SceneFilterPropertyBuilder.java @@ -0,0 +1,43 @@ +package com.ss.builder.fx.control.property.builder.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.filter.EditableSceneFilter; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The property builder to build property controls of editable scene app states. + * + * @author JavaSaBr + */ +public class SceneFilterPropertyBuilder extends EditableModelObjectPropertyBuilder { + + private static final SceneFilterPropertyBuilder INSTANCE = new SceneFilterPropertyBuilder(); + + @FromAnyThread + public static @NotNull SceneFilterPropertyBuilder getInstance() { + return INSTANCE; + } + + protected SceneFilterPropertyBuilder() { + super(ModelChangeConsumer.class); + } + + @Override + @FxThread + protected @Nullable List> getProperties(@NotNull Object object) { + if (object instanceof EditableSceneFilter) { + return ((EditableSceneFilter) object).getEditableProperties(); + } else { + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SpatialPropertyBuilder.java similarity index 83% rename from src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java rename to src/main/java/com/ss/builder/fx/control/property/builder/impl/SpatialPropertyBuilder.java index d34547ea..4fc7034d 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java +++ b/src/main/java/com/ss/builder/fx/control/property/builder/impl/SpatialPropertyBuilder.java @@ -1,21 +1,23 @@ -package com.ss.editor.ui.control.property.builder.impl; +package com.ss.builder.fx.control.property.builder.impl; import static com.ss.editor.extension.property.EditablePropertyType.*; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_LOADED_MODEL; import static com.ss.rlib.common.util.ObjectUtils.ifNull; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.*; import com.ss.editor.extension.scene.SceneLayer; import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.rlib.common.util.array.Array; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.builder.PropertyBuilder; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -90,8 +92,8 @@ private SpatialPropertyBuilder() { } var count = userDataKeys.stream() - .filter(s -> !isNeedSkip(s)) - .count(); + .filter(this::isUserData) + .count(); if (count < 1) { return properties; @@ -99,12 +101,12 @@ private SpatialPropertyBuilder() { properties.add(SeparatorProperty.getInstance()); - final Array sortedKeys = ArrayFactory.newSortedArray(String.class); + var sortedKeys = ArrayFactory.newSortedArray(String.class); sortedKeys.addAll(userDataKeys); for (var key : sortedKeys) { - if (isNeedSkip(key)) { + if (!isUserData(key)) { continue; } @@ -138,12 +140,12 @@ private SpatialPropertyBuilder() { return EditablePropertyType.READ_ONLY_STRING; } - @FxThread - private boolean isNeedSkip(@NotNull String key) { - return SceneLayer.KEY.equals(key) || KEY_LOADED_MODEL.equals(key); + @FromAnyThread + private boolean isUserData(@NotNull String key) { + return !(SceneLayer.KEY.equals(key) || AbstractSceneEditor3dPart.KEY_LOADED_MODEL.equals(key)); } - @FxThread + @FromAnyThread private boolean canEditTransformation(@NotNull Spatial spatial) { return !(spatial instanceof SceneNode || spatial instanceof SceneLayer); } diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/AssetKeyPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/AssetKeyPropertyControl.java new file mode 100644 index 00000000..fa56331f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/AssetKeyPropertyControl.java @@ -0,0 +1,65 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.asset.AssetKey; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The implementation of the {@link PropertyControl} to edit {@link com.jme3.asset.AssetKey}. + * + * @param the change consumer's type. + * @param the edited object's type. + * @param the asset key's generic type. + * @param the asset key's type. + * @author JavaSaBr + */ +public abstract class AssetKeyPropertyControl> + extends KeyPropertyControl { + + + public AssetKeyPropertyControl( + @Nullable A element, + @NotNull String paramName, + @NotNull C changeConsumer + ) { + super(element, paramName, changeConsumer); + setOnDragOver(this::handleDragOverEvent); + setOnDragDropped(this::handleDragDroppedEvent); + setOnDragExited(this::handleDragExitedEvent); + } + + @Override + @FxThread + protected void chooseKey() { + UiUtils.openFileAssetDialog(this::applyNewKey, getExtensions(), DEFAULT_ACTION_TESTER); + super.chooseKey(); + } + + @Override + @FxThread + protected void applyNewKey(@NotNull Path file) { + super.applyNewKey(file); + reload(); + } + + @Override + @FxThread + protected void openKey() { + getPropertyValueOpt().ifPresent(EditorUtils::openInEditor); + super.openKey(); + } + + @Override + @FxThread + protected void reloadImpl() { + keyLabel.setText(EditorUtils.ifEmpty(getPropertyValue(), getNoKeyLabel())); + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/AudioKeyPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/AudioKeyPropertyControl.java new file mode 100644 index 00000000..d508ed45 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/AudioKeyPropertyControl.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioKey; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The implementation of the {@link PropertyControl} to edit the {@link AudioData}. + * + * @param the change consumer's type. + * @param the edited object's type. + * @author JavaSaBr + */ +public class AudioKeyPropertyControl extends + AssetKeyPropertyControl { + + private static final String NO_AUDIO = + Messages.AUDIO_KEY_PROPERTY_CONTROL_NO_AUDIO; + + public AudioKeyPropertyControl( + @Nullable AudioKey element, + @NotNull String paramName, + @NotNull C changeConsumer + ) { + super(element, paramName, changeConsumer); + } + + @Override + @FromAnyThread + protected @NotNull String getNoKeyLabel() { + return NO_AUDIO; + } + + @Override + @FromAnyThread + protected @NotNull Array getExtensions() { + return FileExtensions.AUDIO_EXTENSIONS; + } + + @Override + @FxThread + protected void applyNewKey(@NotNull Path file) { + changed(EditorUtils.realFileToKey(file, AudioKey::new), getPropertyValue()); + super.applyNewKey(file); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/BooleanPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/BooleanPropertyControl.java new file mode 100644 index 00000000..7104dbf6 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/BooleanPropertyControl.java @@ -0,0 +1,124 @@ +package com.ss.builder.fx.control.property.impl; + +import static java.lang.Boolean.TRUE; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.CheckBox; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * The implementation of the {@link PropertyControl} to change boolean values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class BooleanPropertyControl extends PropertyControl { + + /** + * The field with current value. + */ + @NotNull + private final CheckBox checkBox; + + public BooleanPropertyControl( + @Nullable Boolean propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, null); + } + + public BooleanPropertyControl( + @Nullable Boolean propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + this.checkBox = new CheckBox(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + checkBox.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onSelectedChange(checkBox, this::updateValue); + + FxUtils.addClass(checkBox, + CssClasses.PROPERTY_CONTROL_CHECK_BOX); + + FxUtils.addChild(container, checkBox); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + super.changeControlWidthPercent(controlWidthPercent); + + FxUtils.rebindPrefWidth(checkBox, + widthProperty().multiply(controlWidthPercent)); + } + + /** + * Disable the offset of checkbox control. + */ + @FxThread + public void disableCheckboxOffset() { + FxUtils.resetPrefWidth(checkBox); + FxUtils.resetMinMaxWidth(propertyNameLabel) + .prefWidthProperty().bind(widthProperty()); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + @Override + @FxThread + protected void reloadImpl() { + checkBox.setSelected(TRUE.equals(getPropertyValue())); + super.reloadImpl(); + } + + @FxThread + @Override + public boolean isDirty() { + return !Objects.equals(getPropertyValue(), checkBox.isSelected()); + } + + /** + * Update the value. + */ + @FxThread + private void updateValue() { + if (!isIgnoreListener()) { + apply(); + } + } + + @Override + protected void apply() { + super.apply(); + changed(checkBox.isSelected(), getPropertyValue()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/ColorPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/ColorPropertyControl.java new file mode 100644 index 00000000..05242c16 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/ColorPropertyControl.java @@ -0,0 +1,105 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.math.ColorRGBA; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ColorPicker; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit a color values. + * + * @param the change + * @param the type parameter + * @author JavaSaBr + */ +public class ColorPropertyControl extends PropertyControl { + + /** + * The color picker. + */ + @NotNull + private final ColorPicker colorPicker; + + public ColorPropertyControl( + @Nullable ColorRGBA propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.colorPicker = new ColorPicker(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + colorPicker.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onColorChange(colorPicker, this::updateValue); + + FxUtils.addClass(colorPicker, + CssClasses.PROPERTY_CONTROL_COLOR_PICKER); + + FxUtils.addChild(container, colorPicker); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + super.changeControlWidthPercent(controlWidthPercent); + + FxUtils.rebindPrefWidth(colorPicker, + widthProperty().multiply(controlWidthPercent)); + } + + @Override + @FxThread + protected void setPropertyValue(@Nullable ColorRGBA color) { + super.setPropertyValue(color == null ? null : color.clone()); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + @Override + @FxThread + protected void reloadImpl() { + colorPicker.setValue(UiUtils.from(getPropertyValue())); + super.reloadImpl(); + } + + /** + * Updating value. + */ + @FxThread + private void updateValue() { + + if (isIgnoreListener()) { + return; + } + + var newColor = UiUtils.from(colorPicker.getValue()); + var oldValue = getPropertyValue(); + + changed(newColor, oldValue == null ? null : oldValue.clone()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/DefaultPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/DefaultPropertyControl.java new file mode 100644 index 00000000..6d15ee6d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/DefaultPropertyControl.java @@ -0,0 +1,97 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +/** + * The default implementation of the property control. + * + * @param the change consumer's type. + * @param the edited object's type. + * @param the edited property's type. + * @author JavaSaBr + */ +public class DefaultPropertyControl extends PropertyControl { + + /** + * The label with value of the property. + */ + @NotNull + protected final Label propertyValueLabel; + + /** + * The string function. + */ + @Nullable + private Function toStringFunction; + + public DefaultPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.propertyValueLabel = new Label(); + } + + /** + * Set the string function. + * + * @param toStringFunction the string function. + */ + @FromAnyThread + public void setToStringFunction(@Nullable Function toStringFunction) { + this.toStringFunction = toStringFunction; + } + + /** + * Get the string function. + * + * @return the string function. + */ + @FromAnyThread + private @Nullable Function getToStringFunction() { + return toStringFunction; + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + propertyValueLabel.prefWidthProperty() + .bind(container.widthProperty()); + + FxUtils.addClass(propertyValueLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_LABEL_VALUE, + CssClasses.TEXT_INPUT_CONTAINER); + + FxUtils.addChild(container, propertyValueLabel); + } + + @Override + @FxThread + protected void reloadImpl() { + + var function = getToStringFunction(); + var text = function == null ? String.valueOf(getPropertyValue()) : function.apply(getPropertyValue()); + + propertyValueLabel.setText(text); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/DefaultSinglePropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/DefaultSinglePropertyControl.java new file mode 100644 index 00000000..ba8f50ef --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/DefaultSinglePropertyControl.java @@ -0,0 +1,44 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The default implementation of the property control. + * + * @param the change consumer's type. + * @param the edited object's type. + * @param the edited property's type. + * @author JavaSaBr + */ +public class DefaultSinglePropertyControl extends DefaultPropertyControl { + + public DefaultSinglePropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + propertyValueLabel.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/ElementModelPropertyControl.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/ElementModelPropertyControl.java index 69dc98ba..af94cd38 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/ElementModelPropertyControl.java @@ -1,8 +1,11 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/ElementPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/ElementPropertyControl.java new file mode 100644 index 00000000..f8c6ac70 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/ElementPropertyControl.java @@ -0,0 +1,127 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit an elements from scene. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @param the type of an editing property. + * @author JavaSaBr + */ +public class ElementPropertyControl extends PropertyControl { + + protected static final String NO_ELEMENT = Messages.ABSTRACT_ELEMENT_PROPERTY_CONTROL_NO_ELEMENT; + + /** + * The type of an element. + */ + @NotNull + protected final Class type; + + /** + * The label with name of the element. + */ + @NotNull + protected final Label elementLabel; + + public ElementPropertyControl( + @NotNull Class type, + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.type = type; + this.elementLabel = new Label(NO_ELEMENT); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + elementLabel.prefWidthProperty() + .bind(container.widthProperty()); + + var changeButton = new Button(); + changeButton.setGraphic(new ImageView(Icons.ADD_16)); + changeButton.setOnAction(event -> addElement()); + + var removeButton = new Button(); + removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); + removeButton.setOnAction(event -> removeElement()); + removeButton.disableProperty() + .bind(elementLabel.textProperty().isEqualTo(NO_ELEMENT)); + + FxUtils.addClass(container, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) + .addClass(elementLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) + .addClass(changeButton, removeButton, + CssClasses.FLAT_BUTTON, + CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); + + FxControlUtils.onAction(changeButton, this::addElement); + FxControlUtils.onAction(removeButton, this::removeElement); + + FxUtils.addChild(container, + elementLabel, changeButton, removeButton); + + DynamicIconSupport.addSupport(changeButton, removeButton); + } + + /** + * Show a dialog to choose an element. + */ + @FxThread + protected void addElement() { + } + + /** + * Remove the current element. + */ + @FxThread + protected void removeElement() { + changed(null, getPropertyValue()); + } + + @Override + @FxThread + protected void reloadImpl() { + elementLabel.setText(getElementText()); + super.reloadImpl(); + } + + /** + * Get the current element's text. + * + * @return the current element's text. + */ + @FxThread + protected @NotNull String getElementText() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/EnumPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/EnumPropertyControl.java new file mode 100644 index 00000000..691460bf --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/EnumPropertyControl.java @@ -0,0 +1,108 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.builder.util.EditorUtils.getAvailableValues; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit {@link Enum} values. + * + * @param the type of a {@link ChangeConsumer} + * @param the type of an editing object. + * @param the type of editing enum. + * @author JavaSaBr + */ +public class EnumPropertyControl> extends PropertyControl { + + /** + * The list of available options of the {@link Enum} value. + */ + @NotNull + private final ComboBox enumComboBox; + + public EnumPropertyControl( + @Nullable E propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @NotNull E[] availableValues + ) { + this(propertyValue, propertyName, changeConsumer, availableValues, null); + } + + public EnumPropertyControl( + @NotNull E propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, EditorUtils.getAvailableValues(propertyValue), null); + } + + public EnumPropertyControl( + @Nullable E propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @NotNull E[] availableValues, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + this.enumComboBox = new ComboBox<>(); + this.enumComboBox.getItems() + .addAll(availableValues); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + enumComboBox.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onSelectedItemChange(enumComboBox, this::change); + + FxUtils.addClass(enumComboBox, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(container, enumComboBox); + } + + /** + * Update selected {@link Enum} value. + */ + @FxThread + private void change() { + if (!isIgnoreListener()) { + changed(enumComboBox.getValue(), getPropertyValue()); + } + } + + @Override + @FxThread + protected void reloadImpl() { + + enumComboBox.getSelectionModel() + .select(getPropertyValue()); + + super.reloadImpl(); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/FilterElementModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/FilterElementModelPropertyControl.java new file mode 100644 index 00000000..09d31dc1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/FilterElementModelPropertyControl.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.post.Filter; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.dialog.scene.selector.FilterSceneSelectorDialog; +import com.ss.builder.fx.dialog.scene.selector.SceneSelectorDialog; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link SceneElementPropertyControl} to edit light from a scene. + * + * @param the edited object's type. + * @author JavaSaBr + */ +public class FilterElementModelPropertyControl extends SceneElementPropertyControl { + + public FilterElementModelPropertyControl( + @Nullable Filter propertyValue, + @NotNull String propertyName, + @NotNull SceneChangeConsumer changeConsumer + ) { + super(Filter.class, propertyValue, propertyName, changeConsumer); + } + + @Override + @FxThread + protected @NotNull SceneSelectorDialog createSceneSelectorDialog() { + return new FilterSceneSelectorDialog(getChangeConsumer().getCurrentModel(), this::addElement); + } + + @Override + @FxThread + protected @NotNull String getElementText() { + return getPropertyValueOpt() + .map(Filter::getName) + .filter(StringUtils::isNotEmpty) + .or(() -> getPropertyValueOpt() + .map(Filter::getClass) + .map(Class::getSimpleName)) + .orElse(NO_ELEMENT); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/FloatArrayPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/FloatArrayPropertyControl.java new file mode 100644 index 00000000..5ce15471 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/FloatArrayPropertyControl.java @@ -0,0 +1,45 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.FloatArrayTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit float array values. + * + * @param the change consumer's type. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class FloatArrayPropertyControl + extends StringBasedArrayPropertyControl { + + public FloatArrayPropertyControl( + @Nullable float[] propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + } + + public FloatArrayPropertyControl( + @Nullable float[] propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + } + + + @Override + @FromAnyThread + protected @NotNull FloatArrayTextField createFieldControl() { + return new FloatArrayTextField(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/FloatPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/FloatPropertyControl.java new file mode 100644 index 00000000..72ff890b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/FloatPropertyControl.java @@ -0,0 +1,44 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.FloatTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit float values. + * + * @param the change consumer's type. + * @param the editing object's type. + * @author JavaSaBr + */ +public class FloatPropertyControl + extends NumberPropertyControl { + + public FloatPropertyControl( + @Nullable Float propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, null); + } + + public FloatPropertyControl( + @Nullable Float propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + } + + @Override + @FromAnyThread + protected @NotNull FloatTextField createFieldControl() { + return new FloatTextField(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/IntArrayPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/IntArrayPropertyControl.java new file mode 100644 index 00000000..1aacb5df --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/IntArrayPropertyControl.java @@ -0,0 +1,44 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.IntegerArrayTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit int array values. + * + * @param the change consumer's type. + * @param the editing object's type. + * @author JavaSaBr + */ +public class IntArrayPropertyControl + extends StringBasedArrayPropertyControl { + + public IntArrayPropertyControl( + @Nullable int[] propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + } + + public IntArrayPropertyControl( + @Nullable int[] propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + } + + @Override + @FromAnyThread + protected @NotNull IntegerArrayTextField createFieldControl() { + return new IntegerArrayTextField(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/IntegerPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/IntegerPropertyControl.java new file mode 100644 index 00000000..133a31ac --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/IntegerPropertyControl.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.IntegerTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit integer values. + * + * @param the change consumer's type. + * @param the editing object's type. + * @author JavaSaBr + */ +public class IntegerPropertyControl extends + NumberPropertyControl { + + public IntegerPropertyControl( + @Nullable Integer propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + } + + @Override + @FromAnyThread + protected @NotNull IntegerTextField createFieldControl() { + return new IntegerTextField(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/KeyPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/KeyPropertyControl.java new file mode 100644 index 00000000..349eed74 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/KeyPropertyControl.java @@ -0,0 +1,158 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.asset.AssetKey; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The implementation of the {@link PropertyControl} to edit {@link AssetKey}. + * + * @param the change consumer's type. + * @param the edited object's type. + * @param the key's type. + * @author JavaSaBr + */ +public abstract class KeyPropertyControl + extends PropertyControl { + + /** + * The label with name of the audio key. + */ + @NotNull + protected final Label keyLabel; + + public KeyPropertyControl( + @Nullable T element, + @NotNull String paramName, + @NotNull C changeConsumer + ) { + super(element, paramName, changeConsumer); + this.keyLabel = new Label(getNoKeyLabel()); + setOnDragOver(this::handleDragOverEvent); + setOnDragDropped(this::handleDragDroppedEvent); + setOnDragExited(this::handleDragExitedEvent); + } + + /** + * Return the "no key" label. + * + * @return the "no key" label. + */ + @FromAnyThread + protected abstract @NotNull String getNoKeyLabel(); + + /** + * Get a list of extensions of this asset key. + * + * @return the list of extensions of this asset key. + */ + @FromAnyThread + protected abstract @NotNull Array getExtensions(); + + /** + * Handle drag exited events. + * + * @param dragEvent the drag exited event. + */ + @FxThread + protected void handleDragExitedEvent(@NotNull DragEvent dragEvent) { + } + + /** + * Handle dropped events. + * + * @param dragEvent the dropped event. + */ + @FxThread + protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { + UiUtils.handleDroppedFile(dragEvent, this, KeyPropertyControl::applyNewKey); + } + + /** + * Handle drag over events. + * + * @param dragEvent the drag over events. + */ + @FxThread + protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { + UiUtils.acceptIfHasFile(dragEvent, getExtensions()); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + var changeButton = new Button(); + changeButton.setGraphic(new ImageView(Icons.ADD_16)); + + var openButton = new Button(); + openButton.setGraphic(new ImageView(Icons.EDIT_16)); + openButton.disableProperty() + .bind(keyLabel.textProperty().isEqualTo(getNoKeyLabel())); + + keyLabel.prefWidthProperty() + .bind(widthProperty() + .subtract(changeButton.widthProperty()) + .subtract(openButton.widthProperty())); + + FxUtils.addClass(container, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) + .addClass(keyLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) + .addClass(changeButton, openButton, + CssClasses.FLAT_BUTTON, + CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); + + FxControlUtils.onAction(changeButton, this::chooseKey); + FxControlUtils.onAction(openButton, this::openKey); + + FxUtils.addChild(container, + keyLabel, changeButton, openButton); + + DynamicIconSupport.addSupport(changeButton, openButton); + } + + /** + * Show dialog to choose another key. + */ + @FxThread + protected void chooseKey() { + } + + /** + * Add the new key. + * + * @param file the new key. + */ + @FxThread + protected void applyNewKey(@NotNull Path file) { + reload(); + } + + /** + * Open this asset key in an another editor. + */ + @FxThread + protected void openKey() { + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/LayerModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/LayerModelPropertyControl.java new file mode 100644 index 00000000..32bf4407 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/LayerModelPropertyControl.java @@ -0,0 +1,114 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.rlib.common.util.ObjectUtils.ifNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ListCell; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit layers. + * + * @param the type of an editing object. + * @author JavaSaBr + */ +public class LayerModelPropertyControl extends PropertyControl { + + private class LayerCell extends ListCell { + + @Override + protected void updateItem(@Nullable SceneLayer layer, boolean empty) { + super.updateItem(layer, empty); + + if (layer == null || layer == SceneLayer.NO_LAYER) { + setText(Messages.LAYER_PROPERTY_CONTROL_NO_LAYER); + return; + } + + setText(layer.getName()); + } + } + + /** + * The layers combo box. + */ + @NotNull + private final ComboBox layerComboBox; + + public LayerModelPropertyControl( + @Nullable SceneLayer layer, + @NotNull String propertyName, + @NotNull SceneChangeConsumer changeConsumer + ) { + super(ifNull(layer, SceneLayer.NO_LAYER), propertyName, changeConsumer); + this.layerComboBox = new ComboBox<>(); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + layerComboBox.setCellFactory(param -> new LayerCell()); + layerComboBox.setButtonCell(new LayerCell()); + layerComboBox.setEditable(false); + layerComboBox.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onSelectedItemChange(layerComboBox, this::updateLevel); + + FxUtils.addClass(layerComboBox, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(container, layerComboBox); + } + + @FxThread + private void updateLevel(@Nullable SceneLayer layer) { + if (!isIgnoreListener()) { + changed(layer, getPropertyValue()); + } + } + + @Override + @FxThread + protected void reloadImpl() { + + var changeConsumer = (SceneChangeConsumer) getChangeConsumer(); + var currentModel = changeConsumer.getCurrentModel(); + var sceneLayer = getPropertyValue(); + + var items = layerComboBox.getItems(); + items.clear(); + items.add(SceneLayer.NO_LAYER); + items.addAll(currentModel.getLayers()); + + layerComboBox.getSelectionModel() + .select(sceneLayer == null ? SceneLayer.NO_LAYER : sceneLayer); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/LightElementModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/LightElementModelPropertyControl.java new file mode 100644 index 00000000..cd73d2a1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/LightElementModelPropertyControl.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.light.Light; +import com.jme3.post.Filter; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.LightSelectorDialog; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.LightSelectorDialog; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link ElementModelPropertyControl} to edit light from a scene. + * + * @param the edited object's type. + * @author JavaSaBr + */ +public class LightElementModelPropertyControl extends ElementModelPropertyControl { + + public LightElementModelPropertyControl( + @NotNull Class type, + @Nullable L propertyValue, + @NotNull String propertyName, + @NotNull ModelChangeConsumer changeConsumer + ) { + super(type, propertyValue, propertyName, changeConsumer); + } + + @Override + @FxThread + protected @NotNull NodeSelectorDialog createNodeSelectorDialog() { + return new LightSelectorDialog<>(getChangeConsumer().getCurrentModel(), type, this::addElement); + } + + @Override + @FxThread + protected @NotNull String getElementText() { + return getPropertyValueOpt() + .map(Light::getName) + .filter(StringUtils::isNotEmpty) + .or(() -> getPropertyValueOpt() + .map(Light::getClass) + .map(Class::getSimpleName)) + .orElse(NO_ELEMENT); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/LodLevelPropertyControl.java similarity index 77% rename from src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/LodLevelPropertyControl.java index 57afb78c..0e8ce8fe 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/LodLevelPropertyControl.java @@ -1,12 +1,17 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; import com.jme3.scene.Geometry; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.common.util.ObjectUtils; import com.ss.rlib.fx.util.FxControlUtils; import com.ss.rlib.fx.util.FxUtils; @@ -54,8 +59,8 @@ protected void updateItem(@Nullable Integer level, boolean empty) { /** * The lod level combobox. */ - @Nullable - private ComboBox levelComboBox; + @NotNull + private final ComboBox levelComboBox; public LodLevelPropertyControl( @Nullable Integer element, @@ -63,6 +68,7 @@ public LodLevelPropertyControl( @NotNull C changeConsumer ) { super(element, paramName, changeConsumer); + this.levelComboBox = new ComboBox<>(); } @Override @@ -73,10 +79,9 @@ protected boolean isSingleRow() { @Override @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); + protected void createControls(@NotNull HBox container) { + super.createControls(container); - levelComboBox = new ComboBox<>(); levelComboBox.setCellFactory(param -> new LodLevelCell()); levelComboBox.setButtonCell(new LodLevelCell()); levelComboBox.setEditable(false); @@ -98,8 +103,9 @@ protected void createComponents(@NotNull HBox container) { */ @FxThread private void updateLevel(@Nullable Integer newValue) { - if (isIgnoreListener()) return; - changed(ObjectUtils.ifNull(newValue, 0), getPropertyValue()); + if (!isIgnoreListener()) { + changed(ObjectUtils.ifNull(newValue, 0), getPropertyValue()); + } } @Override @@ -108,19 +114,9 @@ private void updateLevel(@Nullable Integer newValue) { return ObjectUtils.ifNull(super.getPropertyValue(), 0); } - /** - * Get the level combo box. - * - * @return The lod level combo box. - */ - @FxThread - protected @NotNull ComboBox getLevelComboBox() { - return ObjectUtils.notNull(levelComboBox); - } - @Override @FxThread - protected void reload() { + protected void reloadImpl() { if (!hasEditObject()) { return; @@ -128,12 +124,12 @@ protected void reload() { var geometry = getEditObject(); var mesh = geometry.getMesh(); + if (mesh == null) { return; } var element = getPropertyValue(); - var levelComboBox = getLevelComboBox(); var items = levelComboBox.getItems(); items.clear(); @@ -149,5 +145,7 @@ protected void reload() { levelComboBox.getSelectionModel() .select(element); + + super.reloadImpl(); } } diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/MaterialKeyPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/MaterialKeyPropertyControl.java new file mode 100644 index 00000000..5c43721c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/MaterialKeyPropertyControl.java @@ -0,0 +1,60 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.asset.MaterialKey; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +/** + * The implementation of the {@link MaterialPropertyControl} to edit the {@link MaterialKey}. + * + * @param the type parameter + * @author JavaSaBr + */ +public class MaterialKeyPropertyControl extends MaterialPropertyControl { + + public MaterialKeyPropertyControl( + @Nullable MaterialKey element, + @NotNull String paramName, + @NotNull C changeConsumer + ) { + super(element, paramName, changeConsumer); + } + + @Override + @FxThread + protected void chooseKey() { + UiUtils.openFileAssetDialog(this::applyNewKey, MATERIAL_EXTENSIONS, DEFAULT_ACTION_TESTER); + super.chooseKey(); + } + + @Override + @FxThread + protected void applyNewKey(@NotNull Path file) { + changed(EditorUtils.realFileToKey(file, MaterialKey::new), getPropertyValue()); + super.applyNewKey(file); + } + + @Override + @FxThread + protected void openKey() { + EditorUtils.openInEditor(getPropertyValue()); + super.openKey(); + } + + @Override + @FxThread + protected void reloadImpl() { + keyLabel.setText(EditorUtils.ifEmpty(getPropertyValue(), NO_MATERIAL)); + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/MaterialPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/MaterialPropertyControl.java new file mode 100644 index 00000000..b098aacf --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/MaterialPropertyControl.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.material.Material; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit the {@link Material}. + * + * @param the change consumer's type. + * @param the edited object's type. + * @param the material's type. + * @author JavaSaBr + */ +public class MaterialPropertyControl extends + KeyPropertyControl { + + protected static final String NO_MATERIAL = + Messages.MATERIAL_MODEL_PROPERTY_CONTROL_NO_MATERIAL; + + protected static final Array MATERIAL_EXTENSIONS = + Array.of(FileExtensions.JME_MATERIAL); + + public MaterialPropertyControl( + @Nullable T element, + @NotNull String paramName, + @NotNull C changeConsumer + ) { + super(element, paramName, changeConsumer); + setOnDragOver(this::handleDragOverEvent); + setOnDragDropped(this::handleDragDroppedEvent); + setOnDragExited(this::handleDragExitedEvent); + } + + @Override + @FromAnyThread + protected @NotNull String getNoKeyLabel() { + return NO_MATERIAL; + } + + @Override + @FromAnyThread + protected @NotNull Array getExtensions() { + return MATERIAL_EXTENSIONS; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/MinMaxPropertyControl.java similarity index 77% rename from src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/MinMaxPropertyControl.java index 187cad10..2eb82981 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/MinMaxPropertyControl.java @@ -1,10 +1,12 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; import static java.lang.Math.max; import static java.lang.Math.min; import com.jme3.math.Vector2f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,8 +25,7 @@ public MinMaxPropertyControl( @NotNull C changeConsumer ) { super(propertyValue, propertyName, changeConsumer); - getXField().setMinMax(0, Integer.MAX_VALUE); - getYField().setMinMax(0, Integer.MAX_VALUE); + setMinMax(0, Integer.MAX_VALUE); } @Override diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/NumberPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/NumberPropertyControl.java new file mode 100644 index 00000000..96999065 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/NumberPropertyControl.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.NumberTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit number values. + * + * @param the change consumer's type. + * @param the editing object's type. + * @param the value's type. + * @param the field's type. + * @author JavaSaBr + */ +public class NumberPropertyControl> extends + TypedTextFieldPropertyControl { + + public NumberPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, null); + } + + public NumberPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + } + + /** + * Set the scroll power. + * + * @param scrollPower the scroll power. + */ + @FxThread + public void setScrollPower(float scrollPower) { + valueField.setScrollPower(scrollPower); + } + + /** + * Get the scroll power. + * + * @return the scroll power. + */ + @FxThread + public float getScrollPower() { + return valueField.getScrollPower(); + } + + /** + * Set the value limits for this field. + * + * @param min the min value. + * @param max the max value. + */ + @FxThread + public void setMinMax(T min, T max) { + valueField.setMinMax(min, max); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/QuaternionPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/QuaternionPropertyControl.java new file mode 100644 index 00000000..b8bb2a66 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/QuaternionPropertyControl.java @@ -0,0 +1,211 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.math.Quaternion; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.LocalObjects; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.LocalObjects; +import com.ss.rlib.common.geom.util.AngleUtils; +import com.ss.rlib.common.util.ExtMath; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.fx.control.input.FloatTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import com.ss.rlib.fx.util.ObservableUtils; +import javafx.scene.control.Label; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; + +/** + * The implementation of the {@link PropertyControl} to edit {@link Quaternion} values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class QuaternionPropertyControl extends PropertyControl { + + /** + * The field Y. + */ + @NotNull + private final FloatTextField xField; + + /** + * The field X. + */ + @NotNull + private final FloatTextField yField; + + /** + * The field Z. + */ + @NotNull + private final FloatTextField zField; + + public QuaternionPropertyControl( + @Nullable Quaternion propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.xField = new FloatTextField(); + this.yField = new FloatTextField(); + this.zField = new FloatTextField(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + var xLabel = new Label("x:"); + + xField.setOnKeyReleased(this::keyReleased); + xField.prefWidthProperty() + .bind(widthProperty().divide(3)); + + var yLabel = new Label("y:"); + + yField.setOnKeyReleased(this::keyReleased); + yField.prefWidthProperty() + .bind(widthProperty().divide(3)); + + var zLabel = new Label("z:"); + + zField.setOnKeyReleased(this::keyReleased); + zField.prefWidthProperty() + .bind(widthProperty().divide(3)); + + FxControlUtils.onValueChange(xField, this::changeValue); + FxControlUtils.onValueChange(yField, this::changeValue); + FxControlUtils.onValueChange(zField, this::changeValue); + + FxUtils.addClass(xLabel, yLabel, zLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_NUMBER_LABEL) + .addClass(container, + CssClasses.DEF_HBOX, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) + .addClass(xField, yField, zField, + CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD, + CssClasses.TRANSPARENT_TEXT_FIELD); + + FxUtils.addChild(container, + xLabel, xField, + yLabel, yField, + zLabel, zField); + + ObservableUtils.onChange(UiUtils.addFocusBinding(container, xField, yField, zField), + this::applyOnLostFocus); + } + + @Override + @FxThread + protected void setPropertyValue(@Nullable Quaternion quaternion) { + super.setPropertyValue(quaternion == null ? null : quaternion.clone()); + } + + @Override + @FxThread + protected void reloadImpl() { + + var angles = LocalObjects.get() + .nextArray3f(); + + var value = getPropertyValue(); + + if (value != null) { + value.toAngles(angles); + } else { + Arrays.fill(angles, 0F); + } + + xField.setValue(AngleUtils.radiansToDegree(angles[0])); + xField.positionCaret(xField.getText().length()); + + yField.setValue(AngleUtils.radiansToDegree(angles[1])); + yField.positionCaret(yField.getText().length()); + + zField.setValue(AngleUtils.radiansToDegree(angles[2])); + zField.positionCaret(zField.getText().length()); + + super.reloadImpl(); + } + + @Override + public boolean isDirty() { + + var angles = LocalObjects.get() + .nextArray3f(); + + var value = getPropertyValue(); + + if (value != null) { + value.toAngles(angles); + } else { + Arrays.fill(angles, 0F); + } + + var x = xField.getPrimitiveValue(); + var y = yField.getPrimitiveValue(); + var z = zField.getPrimitiveValue(); + + return !ExtMath.equals(angles[0], x) || + !ExtMath.equals(angles[1], y) || + !ExtMath.equals(angles[2], z); + } + + /** + * Handle of input the enter key. + */ + @FxThread + private void keyReleased(@NotNull KeyEvent event) { + if (event.getCode() == KeyCode.ENTER) { + changeValue(); + } + } + + /** + * Change value of rotation. + */ + @FxThread + private void changeValue() { + if (!isIgnoreListener()) { + apply(); + } + } + + @Override + @FxThread + protected void apply() { + super.apply(); + + var oldValue = getPropertyValue(); + + if (oldValue != null) { + oldValue = oldValue.clone(); + } + + var x = AngleUtils.degreeToRadians(xField.getPrimitiveValue()); + var y = AngleUtils.degreeToRadians(yField.getPrimitiveValue()); + var z = AngleUtils.degreeToRadians(zField.getPrimitiveValue()); + + var newValue = new Quaternion() + .fromAngles(ArrayFactory.toFloatArray(x, y, z)); + + changed(newValue, oldValue); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/SceneElementPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/SceneElementPropertyControl.java similarity index 80% rename from src/main/java/com/ss/editor/ui/control/property/impl/SceneElementPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/SceneElementPropertyControl.java index e352a8c7..c738babc 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/SceneElementPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/SceneElementPropertyControl.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.dialog.scene.selector.SceneSelectorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.dialog.scene.selector.SceneSelectorDialog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/SpatialElementModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/SpatialElementModelPropertyControl.java new file mode 100644 index 00000000..21f2bd0b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/SpatialElementModelPropertyControl.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.fx.dialog.node.selector.SpatialSelectorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.fx.dialog.node.selector.SpatialSelectorDialog; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link ElementModelPropertyControl} to edit a spatial from a scene. + * + * @param the type of an editing object. + * @param the type of an editing property. + * @author JavaSaBr + */ +public class SpatialElementModelPropertyControl extends ElementModelPropertyControl { + + public SpatialElementModelPropertyControl( + @NotNull Class type, + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull ModelChangeConsumer changeConsumer + ) { + super(type, propertyValue, propertyName, changeConsumer); + } + + @Override + @FxThread + protected @NotNull NodeSelectorDialog createNodeSelectorDialog() { + return new SpatialSelectorDialog<>(getChangeConsumer().getCurrentModel(), type, this::addElement); + } + + @Override + @FxThread + protected @NotNull String getElementText() { + return getPropertyValueOpt() + .map(Spatial::getName) + .filter(StringUtils::isNotEmpty) + .or(() -> getPropertyValueOpt() + .map(Spatial::getClass) + .map(Class::getSimpleName)) + .orElse(NO_ELEMENT); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/StringBasedArrayPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/StringBasedArrayPropertyControl.java new file mode 100644 index 00000000..445d86e3 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/StringBasedArrayPropertyControl.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.rlib.fx.control.input.TypedTextField; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit array values. + * + * @param the change consumer's type. + * @param the editing object's type. + * @param the value's type. + * @param the field's type. + * @author JavaSaBr + */ +public class StringBasedArrayPropertyControl> + extends TypedTextFieldPropertyControl { + + public StringBasedArrayPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + } + + public StringBasedArrayPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/StringPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/StringPropertyControl.java new file mode 100644 index 00000000..8b66b1f4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/StringPropertyControl.java @@ -0,0 +1,104 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.rlib.common.util.StringUtils.emptyIfNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit string values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class StringPropertyControl extends PropertyControl { + + /** + * The filed with current value. + */ + @NotNull + private final TextField valueField; + + public StringPropertyControl( + @Nullable String propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.valueField = new TextField(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + valueField.setOnKeyReleased(this::updateValue); + valueField.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onFocusChange(valueField, this::applyOnLostFocus); + + FxUtils.addClass(valueField, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(container, valueField); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + @Override + @FxThread + protected void reloadImpl() { + + var caretPosition = valueField.getCaretPosition(); + + valueField.setText(emptyIfNull(getPropertyValue())); + valueField.positionCaret(caretPosition); + + super.reloadImpl(); + } + + /** + * Update the value. + */ + @FxThread + private void updateValue(@NotNull KeyEvent event) { + if (!isIgnoreListener() && event.getCode() == KeyCode.ENTER) { + apply(); + } + } + + @FxThread + @Override + public boolean isDirty() { + return !StringUtils.equals(getPropertyValue(), valueField.getText()); + } + + @Override + @FxThread + protected void apply() { + super.apply(); + changed(valueField.getText(), getPropertyValue()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/Texture2dPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/Texture2dPropertyControl.java new file mode 100644 index 00000000..c3748267 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/Texture2dPropertyControl.java @@ -0,0 +1,377 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.builder.FileExtensions.TEXTURE_EXTENSIONS; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_FLIPPED_TEXTURES; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_FLIPPED_TEXTURES; +import static com.ss.editor.extension.property.EditablePropertyType.BOOLEAN; +import static com.ss.editor.extension.property.EditablePropertyType.ENUM; +import static com.ss.builder.util.EditorUtils.*; +import static com.ss.rlib.common.util.ObjectUtils.notNull; + +import com.jme3.asset.AssetKey; +import com.jme3.asset.TextureKey; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.tooltip.ImageChannelPreview; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.tooltip.ImageChannelPreview; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.fx.util.FxUtils; +import javafx.beans.binding.BooleanBinding; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The implementation of the {@link PropertyControl} to edit {@link com.jme3.texture.Texture2D} values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class Texture2dPropertyControl extends PropertyControl { + + protected static final String NO_TEXTURE = + Messages.MATERIAL_MODEL_PROPERTY_CONTROL_NO_TEXTURE; + + protected static final Point DIALOG_SIZE = new Point(600, -1); + + protected static final String PROP_FLIP = "flip"; + protected static final String PROP_WRAP_MODE_S = "wrapModeS"; + protected static final String PROP_WRAP_MODE_T = "wrapModeT"; + protected static final String PROP_MAG_FILTER = "magFilter"; + protected static final String PROP_MIN_FILTER = "minFilter"; + + /** + * The image channels preview. + */ + @NotNull + private final ImageChannelPreview textureTooltip; + + /** + * The image preview. + */ + @NotNull + private final ImageView texturePreview; + + /** + * The label for of path to a texture. + */ + @NotNull + private final Label textureLabel; + + /** + * The field container. + */ + @NotNull + private final HBox fieldContainer; + + public Texture2dPropertyControl( + @Nullable Texture2D propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.fieldContainer = new HBox(); + this.textureTooltip = new ImageChannelPreview(); + this.texturePreview = new ImageView(); + this.textureLabel = new Label(NO_TEXTURE); + setOnDragOver(this::handleDragOverEvent); + setOnDragDropped(this::handleDragDroppedEvent); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + } + + /** + * Handle drag dropped events. + * + * @param dragEvent the drag dropped event. + */ + @FxThread + protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { + UiUtils.handleDroppedFile(dragEvent, this, Texture2dPropertyControl::changeTexture); + } + + /** + * Handle drag over events. + * + * @param dragEvent the drag over event. + */ + @FxThread + protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { + UiUtils.acceptIfHasFile(dragEvent, FileExtensions.TEXTURE_EXTENSIONS); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + if (!isSingleRow()) { + fieldContainer.prefWidthProperty() + .bind(container.widthProperty()); + } + + var previewContainer = new VBox(); + + texturePreview.fitHeightProperty() + .bind(previewContainer.heightProperty()); + texturePreview.fitWidthProperty() + .bind(previewContainer.widthProperty()); + + Tooltip.install(texturePreview, textureTooltip); + + var settingsButton = new Button(); + settingsButton.setGraphic(new ImageView(Icons.SETTINGS_16)); + settingsButton.setOnAction(event -> openSettings()); + settingsButton.disableProperty().bind(buildDisableRemoveCondition()); + + var addButton = new Button(); + addButton.setGraphic(new ImageView(Icons.ADD_12)); + addButton.setOnAction(event -> addNewTexture()); + + var removeButton = new Button(); + removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); + removeButton.setOnAction(event -> removeTexture()); + removeButton.disableProperty().bind(buildDisableRemoveCondition()); + + if (!isSingleRow()) { + + textureLabel.prefWidthProperty() + .bind(widthProperty() + .subtract(removeButton.widthProperty()) + .subtract(previewContainer.widthProperty()) + .subtract(settingsButton.widthProperty()) + .subtract(addButton.widthProperty())); + + FxUtils.addClass(textureLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) + .addClass(fieldContainer, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER); + + FxUtils.addChild(fieldContainer, textureLabel); + + } else { + FxUtils.addClass(fieldContainer, + CssClasses.TEXT_INPUT_CONTAINER_WITHOUT_PADDING); + } + + FxUtils.addClass(previewContainer, + CssClasses.ABSTRACT_PARAM_CONTROL_PREVIEW_CONTAINER) + .addClass(settingsButton, addButton, removeButton, + CssClasses.FLAT_BUTTON, + CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); + + FxUtils.addChild(fieldContainer, previewContainer, addButton, settingsButton, removeButton) + .addChild(container, fieldContainer) + .addChild(previewContainer, texturePreview); + } + + /** + * Get the disable|remove condition. + * + * @return the disable|remove condition. + */ + @FxThread + protected @NotNull BooleanBinding buildDisableRemoveCondition() { + return texturePreview.imageProperty() + .isNull(); + } + + /** + * Remove the current texture. + */ + @FxThread + protected void removeTexture() { + changeTexture(null); + } + + /** + * Open the dialog to choose a new texture. + */ + @FxThread + protected void addNewTexture() { + UiUtils.openFileAssetDialog(this::changeTexture, FileExtensions.TEXTURE_EXTENSIONS, DEFAULT_ACTION_TESTER); + } + + /** + * Open a dialog with texture's settings. + */ + @FxThread + protected void openSettings() { + + var texture = notNull(getPropertyValue()); + var key = (TextureKey) texture.getKey(); + var flipY = key.isFlipY(); + var wrapS = texture.getWrap(Texture.WrapAxis.S); + var wrapT = texture.getWrap(Texture.WrapAxis.T); + var magFilter = texture.getMagFilter(); + var minFilter = texture.getMinFilter(); + + var properties = ArrayFactory.newArray(PropertyDefinition.class); + properties.add(new PropertyDefinition(BOOLEAN, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_FLIP_Y, PROP_FLIP, flipY)); + properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_WRAP_MODE_S, PROP_WRAP_MODE_S, wrapS)); + properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_WRAP_MODE_T, PROP_WRAP_MODE_T, wrapT)); + properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_MAG_FILTER, PROP_MAG_FILTER, magFilter)); + properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_MIN_FILTER, PROP_MIN_FILTER, minFilter)); + + var dialog = new GenericFactoryDialog(properties, this::applyChanges); + dialog.setTitle(Messages.MATERIAL_MODEL_PROPERTY_CONTROL_TEXTURE_SETTINGS); + dialog.setButtonOkText(Messages.SIMPLE_DIALOG_BUTTON_APPLY); + dialog.setButtonCloseText(Messages.SIMPLE_DIALOG_BUTTON_CANCEL); + dialog.configureSize(DIALOG_SIZE); + dialog.show(); + } + + /** + * Apply new changes if need. + * + * @param vars the vars table. + */ + @FxThread + private void applyChanges(@NotNull VarTable vars) { + + var texture = notNull(getPropertyValue()); + var key = (TextureKey) texture.getKey(); + var flipY = key.isFlipY(); + var wrapS = texture.getWrap(Texture.WrapAxis.S); + var wrapT = texture.getWrap(Texture.WrapAxis.T); + var magFilter = texture.getMagFilter(); + var minFilter = texture.getMinFilter(); + + var needFlipY = vars.getBoolean(PROP_FLIP); + var needWrapS = vars.getEnum(PROP_WRAP_MODE_S, Texture.WrapMode.class); + var needWrapT = vars.getEnum(PROP_WRAP_MODE_T, Texture.WrapMode.class); + var needMagFilter = vars.getEnum(PROP_MAG_FILTER, Texture.MagFilter.class); + var needMinFilter = vars.getEnum(PROP_MIN_FILTER, Texture.MinFilter.class); + + if (flipY == needFlipY && + wrapS == needWrapS && + wrapT == needWrapT && + magFilter == needMagFilter && + minFilter == needMinFilter) { + return; + } + + var newKey = new TextureKey(key.getName()); + newKey.setFlipY(needFlipY); + + var assetManager = EditorUtils.getAssetManager(); + assetManager.deleteFromCache(key); + + var loadedTexture = (Texture2D) assetManager.loadTexture(newKey); + loadedTexture.setWrap(Texture.WrapAxis.S, needWrapS); + loadedTexture.setWrap(Texture.WrapAxis.T, needWrapT); + loadedTexture.setMagFilter(needMagFilter); + loadedTexture.setMinFilter(needMinFilter); + + changed(loadedTexture, texture); + } + + /** + * Change a texture to the file. + * + * @param file the file of a new texture. + */ + @FxThread + protected void changeTexture(@Nullable Path file) { + + if (file == null) { + changed(null, getPropertyValue()); + } else { + + var config = EditorConfig.getInstance(); + var assetFile = notNull(EditorUtils.getAssetFile(file)); + var textureKey = new TextureKey(EditorUtils.toAssetPath(assetFile)); + textureKey.setFlipY(config.getBoolean(DefaultSettingsProvider.Preferences.PREF_FLIPPED_TEXTURES, DefaultSettingsProvider.Defaults.PREF_DEFAULT_FLIPPED_TEXTURES)); + + var texture = (Texture2D) EditorUtils.getAssetManager() + .loadTexture(textureKey); + texture.setWrap(Texture.WrapMode.Repeat); + + changed(texture, getPropertyValue()); + } + } + + @Override + @FxThread + protected void reloadImpl() { + + var assetKey = getPropertyValueOpt() + .map(Texture::getKey); + + if (!isSingleRow()) { + textureLabel.setText(assetKey.map(AssetKey::getName) + .orElse(NO_TEXTURE)); + } + + assetKey.ifPresentOrElse(this::loadTexture, this::clearTexture); + + super.reloadImpl(); + } + + @FxThread + private void loadTexture(@NotNull AssetKey key) { + + texturePreview.setDisable(false); + texturePreview.setMouseTransparent(false); + + var realFile = EditorUtils.requireRealFile(key); + var imageManager = JavaFxImageManager.getInstance(); + + if (Files.exists(realFile)) { + texturePreview.setImage(imageManager.getImagePreview(realFile, 24, 24)); + textureTooltip.showImage(realFile); + } else { + texturePreview.setImage(imageManager.getImagePreview(key.getName(), 24, 24)); + textureTooltip.showImage(key.getName()); + } + } + + @FxThread + private void clearTexture() { + texturePreview.setImage(null); + textureTooltip.clean(); + texturePreview.setDisable(true); + texturePreview.setMouseTransparent(true); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Texture2dSingleRowPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/Texture2dSingleRowPropertyControl.java similarity index 75% rename from src/main/java/com/ss/editor/ui/control/property/impl/Texture2dSingleRowPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/Texture2dSingleRowPropertyControl.java index 4242ca02..8cfb2569 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Texture2dSingleRowPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/Texture2dSingleRowPropertyControl.java @@ -1,8 +1,10 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; import com.jme3.texture.Texture2D; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/TypedTextFieldPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/TypedTextFieldPropertyControl.java new file mode 100644 index 00000000..4f00ca65 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/TypedTextFieldPropertyControl.java @@ -0,0 +1,133 @@ +package com.ss.builder.fx.control.property.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.control.input.TypedTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * The typed text field based implementation of the {@link PropertyControl}. + * + * @param the change consumer's type. + * @param the editing object's type. + * @param the value's type. + * @param the field's type. + * @author JavaSaBr + */ +public class TypedTextFieldPropertyControl> extends PropertyControl { + + /** + * The filed with current value. + */ + @NotNull + protected final F valueField; + + public TypedTextFieldPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, null); + } + + public TypedTextFieldPropertyControl( + @Nullable T propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + this.valueField = createFieldControl(); + } + + /** + * Create a text field control. + * + * @return the text field control. + */ + @FromAnyThread + protected @NotNull F createFieldControl() { + throw new UnsupportedOperationException(); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + super.changeControlWidthPercent(controlWidthPercent); + + FxUtils.rebindPrefWidth(valueField, + widthProperty().multiply(controlWidthPercent)); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + valueField.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + FxControlUtils.onValueChange(valueField, this::updateValue); + FxControlUtils.onFocusChange(valueField, this::applyOnLostFocus); + + FxUtils.addClass(valueField, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(container, valueField); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + @Override + @FxThread + protected void reloadImpl() { + + var caretPosition = valueField.getCaretPosition(); + + valueField.setValue(getPropertyValue()); + valueField.positionCaret(caretPosition); + + super.reloadImpl(); + } + + @Override + @FxThread + public boolean isDirty() { + return !Objects.equals(valueField.getValue(), getPropertyValue()); + } + + /** + * Update the value. + */ + @FxThread + private void updateValue() { + if (!isIgnoreListener()) { + apply(); + } + } + + @Override + @FxThread + protected void apply() { + super.apply(); + changed(valueField.getValue(), getPropertyValue()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/Vector2fPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/Vector2fPropertyControl.java new file mode 100644 index 00000000..764cd37d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/Vector2fPropertyControl.java @@ -0,0 +1,226 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.builder.util.GeomUtils.zeroIfNull; +import com.jme3.math.Vector2f; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.rlib.fx.control.input.FloatTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit {@link Vector2f} values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class Vector2fPropertyControl extends PropertyControl { + + /** + * The field X. + */ + @NotNull + protected final FloatTextField xField; + + /** + * The field Y. + */ + @NotNull + protected final FloatTextField yField; + + /** + * The field container. + */ + @NotNull + private final HBox fieldContainer; + + public Vector2fPropertyControl( + @Nullable Vector2f propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.fieldContainer = new HBox(); + this.xField = new FloatTextField(); + this.yField = new FloatTextField(); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + super.changeControlWidthPercent(controlWidthPercent); + + FxUtils.rebindPrefWidth(fieldContainer, + widthProperty().multiply(controlWidthPercent)); + } + + /** + * Set value limits for this field. + * + * @param min the min value. + * @param max the max value. + */ + @FxThread + public void setMinMax(float min, float max) { + xField.setMinMax(min, max); + yField.setMinMax(min, max); + } + + /** + * Sets the scroll power. + * + * @param scrollPower the scroll power. + */ + @FxThread + public void setScrollPower(float scrollPower) { + xField.setScrollPower(scrollPower); + yField.setScrollPower(scrollPower); + } + + /** + * Get the scroll power. + * + * @return the scroll power. + */ + @FxThread + public float getScrollPower() { + return xField.getScrollPower(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + fieldContainer.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + xField.setOnKeyReleased(this::updateVector); + xField.setScrollPower(10F); + xField.prefWidthProperty() + .bind(fieldContainer.widthProperty().multiply(0.5)); + + yField.setOnKeyReleased(this::updateVector); + yField.setScrollPower(10F); + yField.prefWidthProperty() + .bind(fieldContainer.widthProperty().multiply(0.5)); + + FxUtils.addClass(fieldContainer, + CssClasses.DEF_HBOX, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_SHORT_INPUT_CONTAINER) + .addClass(xField, yField, + CssClasses.TRANSPARENT_TEXT_FIELD); + + FxControlUtils.onValueChange(xField, () -> updateVector(null)); + FxControlUtils.onValueChange(yField, () -> updateVector(null)); + + FxUtils.addChild(fieldContainer, xField, yField) + .addChild(container, fieldContainer); + + UiUtils.addFocusBinding(fieldContainer, xField, yField) + .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); + } + + @Override + @FxThread + protected void setPropertyValue(@Nullable Vector2f vector) { + super.setPropertyValue(GeomUtils.zeroIfNull(vector).clone()); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } + + /** + * Check the result x value. + * + * @param x the x. + * @param y the y. + * @return the result x value. + */ + @FxThread + protected float checkResultXValue(float x, float y) { + return x; + } + + /** + * Check result y value. + * + * @param x the x. + * @param y the y. + * @return the result y value. + */ + @FxThread + protected float checkResultYValue(float x, float y) { + return y; + } + + @Override + @FxThread + protected void reloadImpl() { + + var vector = zeroIfNull(getPropertyValue()); + + xField.setValue(vector.getX()); + xField.positionCaret(xField.getText().length()); + + yField.setValue(vector.getY()); + yField.positionCaret(yField.getText().length()); + + super.reloadImpl(); + } + + @Override + @FxThread + public boolean isDirty() { + var x = xField.getPrimitiveValue(); + var y = yField.getPrimitiveValue(); + return !GeomUtils.equals(getPropertyValue(), x, y); + } + + /** + * Update the vector. + * + * @param event the event + */ + @FxThread + private void updateVector(@Nullable KeyEvent event) { + if (!isIgnoreListener() && (event == null || event.getCode() == KeyCode.ENTER)) { + apply(); + } + } + + @Override + @FxThread + protected void apply() { + super.apply(); + + var x = xField.getPrimitiveValue(); + var y = yField.getPrimitiveValue(); + + var oldValue = zeroIfNull(getPropertyValue()); + var newValue = new Vector2f(checkResultXValue(x, y), checkResultYValue(x, y)); + + changed(newValue, oldValue.clone()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fPropertyControl.java new file mode 100644 index 00000000..9e6249e0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fPropertyControl.java @@ -0,0 +1,243 @@ +package com.ss.builder.fx.control.property.impl; + +import static com.ss.builder.util.GeomUtils.zeroIfNull; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.rlib.fx.control.input.FloatTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Label; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit {@link Vector3f} values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr + */ +public class Vector3fPropertyControl extends PropertyControl { + + /** + * The field X. + */ + @NotNull + protected final FloatTextField xField; + + /** + * The field Y. + */ + @NotNull + protected final FloatTextField yField; + + /** + * The field Z. + */ + @NotNull + protected final FloatTextField zField; + + public Vector3fPropertyControl( + @Nullable Vector3f propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + this(propertyValue, propertyName, changeConsumer, null); + } + + public Vector3fPropertyControl( + @Nullable Vector3f propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer, + @Nullable ChangeHandler changeHandler + ) { + super(propertyValue, propertyName, changeConsumer, changeHandler); + this.xField = new FloatTextField(); + this.yField = new FloatTextField(); + this.zField = new FloatTextField(); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + super.createControls(container); + + var xLabel = new Label("x:"); + + xField.setOnKeyReleased(this::keyReleased); + xField.setScrollPower(getScrollPower()); + xField.prefWidthProperty(). + bind(widthProperty().divide(3)); + + var yLabel = new Label("y:"); + + yField.setOnKeyReleased(this::keyReleased); + yField.setScrollPower(getScrollPower()); + yField.prefWidthProperty() + .bind(widthProperty().divide(3)); + + var zLabel = new Label("z:"); + + zField.setOnKeyReleased(this::keyReleased); + zField.setScrollPower(getScrollPower()); + zField.prefWidthProperty() + .bind(widthProperty().divide(3)); + + FxControlUtils.onValueChange(xField, this::changeValue); + FxControlUtils.onValueChange(yField, this::changeValue); + FxControlUtils.onValueChange(zField, this::changeValue); + + FxUtils.addClass(xLabel, yLabel, zLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_NUMBER_LABEL) + .addClass(container, + CssClasses.DEF_HBOX, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) + .addClass(xField, yField, zField, + CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD, + CssClasses.TRANSPARENT_TEXT_FIELD); + + FxUtils.addChild(container, + xLabel, xField, + yLabel, yField, + zLabel, zField); + + UiUtils.addFocusBinding(container, xField, yField, zField) + .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); + } + + @Override + @FxThread + protected void setPropertyValue(@Nullable Vector3f vector) { + super.setPropertyValue(GeomUtils.zeroIfNull(vector).clone()); + } + + /** + * Get the scroll power. + * + * @return the scroll power. + */ + @FxThread + protected float getScrollPower() { + return 10F; + } + + /** + * Check result x value. + * + * @param x the x. + * @param y the y. + * @param z the z. + * @return the result x value. + */ + @FxThread + protected float checkResultXValue(float x, float y, float z) { + return x; + } + + /** + * Check result y value. + * + * @param x the x. + * @param y the y. + * @param z the z. + * @return the result y value. + */ + @FxThread + protected float checkResultYValue(float x, float y, float z) { + return y; + } + + /** + * Check result z value. + * + * @param x the x. + * @param y the y. + * @param z the z. + * @return the result z value. + */ + @FxThread + protected float checkResultZValue(float x, float y, float z) { + return z; + } + + + @Override + @FxThread + protected void reloadImpl() { + + var vector = zeroIfNull(getPropertyValue()); + + xField.setValue(vector.getX()); + xField.positionCaret(xField.getText().length()); + + yField.setValue(vector.getY()); + yField.positionCaret(xField.getText().length()); + + zField.setValue(vector.getZ()); + zField.positionCaret(xField.getText().length()); + + super.reloadImpl(); + } + + @Override + @FxThread + public boolean isDirty() { + + var x = xField.getPrimitiveValue(); + var y = yField.getPrimitiveValue(); + var z = zField.getPrimitiveValue(); + + return !GeomUtils.equals(getPropertyValue(), x, y, z); + } + + /** + * Handle of input the enter key. + */ + @FxThread + protected void keyReleased(@NotNull KeyEvent event) { + if (event.getCode() == KeyCode.ENTER) { + changeValue(); + } + } + + /** + * Change value of vector. + */ + @FxThread + protected void changeValue() { + if (!isIgnoreListener()) { + apply(); + } + } + + @Override + @FxThread + protected void apply() { + super.apply(); + + var x = xField.getPrimitiveValue(); + var y = yField.getPrimitiveValue(); + var z = zField.getPrimitiveValue(); + + var storedValue = zeroIfNull(getPropertyValue()); + var newValue = new Vector3f(); + newValue.set(checkResultXValue(x, y, z), checkResultYValue(x, y, z), checkResultZValue(x, y, z)); + + changed(newValue, storedValue.clone()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fSingleRowPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fSingleRowPropertyControl.java new file mode 100644 index 00000000..7332de1d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/Vector3fSingleRowPropertyControl.java @@ -0,0 +1,99 @@ +package com.ss.builder.fx.control.property.impl; + +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.property.PropertyControl; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyControl} to edit {@link com.jme3.math.Vector3f} values. + * + * @param the type of a change consumer. + * @param the type of an editing object. + * @author JavaSaBr. + */ +public class Vector3fSingleRowPropertyControl extends Vector3fPropertyControl { + + /** + * The field container. + */ + @NotNull + private final HBox fieldContainer; + + public Vector3fSingleRowPropertyControl( + @Nullable Vector3f propertyValue, + @NotNull String propertyName, + @NotNull C changeConsumer + ) { + super(propertyValue, propertyName, changeConsumer); + this.fieldContainer = new HBox(); + } + + @Override + @FxThread + public void changeControlWidthPercent(double controlWidthPercent) { + super.changeControlWidthPercent(controlWidthPercent); + + FxUtils.rebindPrefWidth(fieldContainer, + widthProperty().multiply(controlWidthPercent)); + } + + @Override + @FxThread + protected void createControls(@NotNull HBox container) { + + fieldContainer.prefWidthProperty() + .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); + + xField.setOnKeyReleased(this::keyReleased); + xField.setScrollPower(10F); + xField.prefWidthProperty(). + bind(fieldContainer.widthProperty().multiply(0.33)); + + yField.setOnKeyReleased(this::keyReleased); + yField.setScrollPower(10F); + yField.prefWidthProperty() + .bind(fieldContainer.widthProperty().multiply(0.33)); + + zField.setOnKeyReleased(this::keyReleased); + zField.setScrollPower(10F); + zField.prefWidthProperty() + .bind(fieldContainer.widthProperty().multiply(0.33)); + + FxControlUtils.onValueChange(xField, this::changeValue); + FxControlUtils.onValueChange(yField, this::changeValue); + FxControlUtils.onValueChange(zField, this::changeValue); + + FxUtils.addClass(fieldContainer, + CssClasses.DEF_HBOX, + CssClasses.TEXT_INPUT_CONTAINER, + CssClasses.ABSTRACT_PARAM_CONTROL_SHORT_INPUT_CONTAINER) + .addClass(xField, yField, zField, + CssClasses.TRANSPARENT_TEXT_FIELD); + + FxUtils.addChild(fieldContainer, xField, yField, zField) + .addChild(container, fieldContainer); + + UiUtils.addFocusBinding(fieldContainer, xField, yField, zField) + .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); + } + + @Override + @FromAnyThread + protected boolean isSingleRow() { + return true; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/WheelElementModelPropertyControl.java similarity index 75% rename from src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java rename to src/main/java/com/ss/builder/fx/control/property/impl/WheelElementModelPropertyControl.java index ca29a3a6..368eb92b 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java +++ b/src/main/java/com/ss/builder/fx/control/property/impl/WheelElementModelPropertyControl.java @@ -1,13 +1,17 @@ -package com.ss.editor.ui.control.property.impl; +package com.ss.builder.fx.control.property.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.bullet.control.VehicleControl; import com.jme3.bullet.objects.VehicleWheel; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.dialog.node.selector.NodeSelectorDialog; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.util.NodeUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,9 +34,12 @@ public WheelElementModelPropertyControl( @Override @FxThread protected @NotNull NodeSelectorDialog createNodeSelectorDialog() { - var changeConsumer = getChangeConsumer(); - var currentModel = changeConsumer.getCurrentModel(); + + var currentModel = getChangeConsumer() + .getCurrentModel(); + var root = NodeUtils.findSpatial(currentModel, this::checkSpatial); + return new NodeSelectorDialog<>(notNull(root), type, this::addElement); } @@ -45,6 +52,7 @@ public WheelElementModelPropertyControl( private boolean checkSpatial(@NotNull Spatial spatial) { var control = spatial.getControl(VehicleControl.class); + if (control == null) { return false; } diff --git a/src/main/java/com/ss/builder/fx/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java b/src/main/java/com/ss/builder/fx/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java new file mode 100644 index 00000000..79da2b1f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.property.impl.particle; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.math.Vector2f; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.property.impl.Vector2fPropertyControl; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link Vector2fPropertyControl} to edit images count of the {@link + * ParticleEmitter}*. + * + * @author JavaSaBr. + */ +public class ParticleEmitterImagesModelPropertyControl extends + Vector2fPropertyControl { + + public ParticleEmitterImagesModelPropertyControl( + @NotNull Vector2f element, + @NotNull String paramName, + @NotNull ModelChangeConsumer changeConsumer + ) { + super(element, paramName, changeConsumer); + setMinMax(1, Integer.MAX_VALUE); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/property/operation/PropertyCountOperation.java b/src/main/java/com/ss/builder/fx/control/property/operation/PropertyCountOperation.java new file mode 100644 index 00000000..66108260 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/operation/PropertyCountOperation.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.property.operation; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link PropertyOperation} to edit property count of objects. + * + * @param the type of changed consumer + * @param the type of edited object + * @param the type of edited property + * @author JavaSaBr + */ +public class PropertyCountOperation extends PropertyOperation { + + public PropertyCountOperation( + @NotNull D target, + @NotNull String propertyName, + @Nullable T newValue, + @Nullable T oldValue + ) { + super(target, propertyName, newValue, oldValue); + } + + @Override + @JmeThread + protected void redoInJme(@NotNull C editor) { + super.redoInJme(editor); + apply(target, newValue); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull C editor) { + super.undoInJme(editor); + apply(target, oldValue); + } + + @Override + @FxThread + protected void endInFx(@NotNull C editor) { + super.endInFx(editor); + editor.notifyFxChangePropertyCount(target); + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/control/property/operation/PropertyOperation.java b/src/main/java/com/ss/builder/fx/control/property/operation/PropertyOperation.java new file mode 100644 index 00000000..2229360b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/property/operation/PropertyOperation.java @@ -0,0 +1,134 @@ +package com.ss.builder.fx.control.property.operation; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiConsumer; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to edit properties of objects. + * + * @param the type of changed consumer + * @param the type of edited object + * @param the type of edited property + * @author JavaSaBr + */ +public class PropertyOperation extends AbstractEditorOperation { + + /** + * The property name. + */ + @NotNull + protected final String propertyName; + + /** + * The new value of the property. + */ + @Nullable + protected final T newValue; + + /** + * The old value of the property. + */ + @Nullable + protected final T oldValue; + + /** + * The target object. + */ + @NotNull + protected final D target; + + /** + * The handler for applying new value. + */ + @Nullable + private volatile BiConsumer applyHandler; + + public PropertyOperation( + @NotNull D target, + @NotNull String propertyName, + @Nullable T newValue, + @Nullable T oldValue + ) { + + this.newValue = newValue; + this.oldValue = oldValue; + this.target = target; + this.propertyName = propertyName; + } + + @Override + @JmeThread + protected void startInJme(@NotNull C editor) { + super.startInJme(editor); + editor.notifyJmePreChangeProperty(target, propertyName); + } + + @Override + @JmeThread + protected void endInJme(@NotNull C editor) { + super.endInJme(editor); + editor.notifyJmeChangedProperty(target, propertyName); + } + + @Override + @JmeThread + protected void redoInJme(@NotNull C editor) { + super.redoInJme(editor); + apply(target, newValue); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull C editor) { + super.undoInJme(editor); + apply(target, oldValue); + } + + @Override + @FxThread + protected void endInFx(@NotNull C editor) { + super.endInFx(editor); + editor.notifyFxChangeProperty(target, propertyName); + } + + /** + * Sets apply handler. + * + * @param applyHandler the handler for applying new value. + */ + @FromAnyThread + public void setApplyHandler(@NotNull BiConsumer applyHandler) { + this.applyHandler = applyHandler; + } + + /** + * Apply new value of the property to the model. + * + * @param spatial the spatial + * @param value the value + */ + @JmeThread + protected void apply(@NotNull D spatial, @Nullable T value) { + try { + notNull(applyHandler).accept(spatial, value); + } catch (Exception e) { + EditorUtils.handleException(LOGGER, this, e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/control/scene/SceneNodeTree.java b/src/main/java/com/ss/builder/fx/control/scene/SceneNodeTree.java new file mode 100644 index 00000000..f02fa388 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/scene/SceneNodeTree.java @@ -0,0 +1,23 @@ +package com.ss.builder.fx.control.scene; + +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.control.SelectionMode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * The implementation of {@link NodeTree} to present scene's objects. + * + * @author JavaSaBr + */ +public class SceneNodeTree extends NodeTree { + + public SceneNodeTree(@NotNull final Consumer> selectionHandler, @Nullable final SceneChangeConsumer consumer) { + super(selectionHandler, consumer, SelectionMode.SINGLE); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java b/src/main/java/com/ss/builder/fx/control/tree/NodeTree.java similarity index 76% rename from src/main/java/com/ss/editor/ui/control/tree/NodeTree.java rename to src/main/java/com/ss/builder/fx/control/tree/NodeTree.java index fc6d54be..f70f7a16 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java +++ b/src/main/java/com/ss/builder/fx/control/tree/NodeTree.java @@ -1,20 +1,17 @@ -package com.ss.editor.ui.control.tree; +package com.ss.builder.fx.control.tree; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactoryRegistry; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.LocalObjects; -import com.ss.rlib.common.function.TripleConsumer; -import com.ss.rlib.fx.util.FXUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactoryRegistry; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayCollectors; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.beans.value.ObservableValue; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; import javafx.collections.ObservableList; import javafx.scene.control.*; import javafx.scene.layout.VBox; @@ -23,6 +20,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.Consumer; /** @@ -33,24 +31,24 @@ */ public class NodeTree extends VBox { - /** - * The executor manager. - */ - @NotNull protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The tree node factory. - */ - @NotNull protected static final TreeNodeFactoryRegistry FACTORY_REGISTRY = TreeNodeFactoryRegistry.getInstance(); + @FunctionalInterface + public interface MultiItemActionFiller { + + @FxThread + void fill( + @NotNull NodeTree nodeTree, + @NotNull List menuItems, + @NotNull Array> treeNodes + ); + } /** * The list of action fillers. */ - @NotNull - private static final Array, List, Array>>> MULTI_ITEMS_ACTION_FILLERS = - ArrayFactory.newArray(TripleConsumer.class); + private static final Array MULTI_ITEMS_ACTION_FILLERS = + Array.ofType(MultiItemActionFiller.class); /** * Register the new multi items action filler. @@ -58,7 +56,7 @@ public class NodeTree extends VBox { * @param actionFiller the new multi items action filler. */ @FxThread - public static void register(@NotNull final TripleConsumer, List, Array>> actionFiller) { + public static void register(@NotNull MultiItemActionFiller actionFiller) { MULTI_ITEMS_ACTION_FILLERS.add(actionFiller); } @@ -86,17 +84,20 @@ public static void register(@NotNull final TripleConsumer, List> treeView; - public NodeTree(@NotNull final Consumer> selectionHandler, @Nullable final C consumer) { + public NodeTree(@NotNull Consumer> selectionHandler, @Nullable C consumer) { this(selectionHandler, consumer, SelectionMode.SINGLE); } - public NodeTree(@NotNull final Consumer> selectionHandler, @Nullable final C consumer, - @NotNull final SelectionMode selectionMode) { + public NodeTree( + @NotNull Consumer> selectionHandler, + @Nullable C consumer, + @NotNull SelectionMode selectionMode + ) { this.selectionHandler = selectionHandler; this.changeConsumer = consumer; this.selectionMode = selectionMode; createComponents(); - FXUtils.addClassTo(this, CssClasses.ABSTRACT_NODE_TREE_CONTAINER); + FxUtils.addClass(this, CssClasses.ABSTRACT_NODE_TREE_CONTAINER); } /** @@ -113,11 +114,12 @@ protected void createComponents() { treeView.prefHeightProperty().bind(heightProperty()); treeView.prefWidthProperty().bind(widthProperty()); - final MultipleSelectionModel>> selectionModel = treeView.getSelectionModel(); + var selectionModel = treeView.getSelectionModel(); selectionModel.setSelectionMode(selectionMode); - selectionModel.selectedItemProperty().addListener(this::updateSelection); - FXUtils.addToPane(treeView, this); + FxControlUtils.onSelectedItemChange(treeView, treeNodeTreeItem -> updateSelection()); + + FxUtils.addChild(this, treeView); } /** @@ -134,21 +136,14 @@ protected void createComponents() { * Select the item. */ @FxThread - private void updateSelection(@NotNull final ObservableValue>> observable, - @Nullable final TreeItem> oldValue, - @Nullable final TreeItem> treeItem) { + private void updateSelection() { - final ObservableList>> selectedItems = getTreeView() + var objects = getTreeView() .getSelectionModel() - .getSelectedItems(); - - final Array objects = LocalObjects.get().nextObjectArray(); - objects.clear(); - - for (final TreeItem> selectedItem : selectedItems) { - if (selectedItem == null) continue; - objects.add(selectedItem.getValue()); - } + .getSelectedItems() + .stream() + .map(TreeItem::getValue) + .collect(ArrayCollectors.toArray(Object.class)); selectionHandler.accept(objects); } @@ -216,7 +211,7 @@ private void fill(@NotNull TreeItem> treeItem, boolean expanded, int * @param level the level. */ @FxThread - public void expandToLevel(final int level) { + public void expandToLevel(int level) { expandToLevel(getTreeView().getRoot(), 0, level); } @@ -228,7 +223,7 @@ public void expandToLevel(final int level) { * @param level the level. */ @FxThread - private void expandToLevel(final TreeItem> item, final int currentLevel, final int level) { + private void expandToLevel(TreeItem> item, int currentLevel, int level) { item.setExpanded(currentLevel <= level); item.getChildren().forEach(child -> expandToLevel(child, currentLevel + 1, level)); } @@ -239,26 +234,26 @@ private void expandToLevel(final TreeItem> item, final int currentLe * @param object the object. */ @FxThread - public void refresh(@NotNull final Object object) { + public void refresh(@NotNull Object object) { - final TreeItem> treeItem = findItemForValue(getTreeView(), object); + var treeItem = UiUtils.findItemForValue(getTreeView(), object); if (treeItem == null) { return; } - final TreeNode treeNode = treeItem.getValue(); - final ObservableList>> items = treeItem.getChildren(); + var treeNode = treeItem.getValue(); + var items = treeItem.getChildren(); items.clear(); - final boolean expanded = treeItem.isExpanded(); - final TreeNode selected = getSelected(); + var expanded = treeItem.isExpanded(); + var selected = getSelected(); - final TreeNode element = treeItem.getValue(); + var element = treeItem.getValue(); if (!element.hasChildren(this)) { return; } - final Array> children = element.getChildren(this); + var children = element.getChildren(this); children.forEach(child -> items.add(new TreeItem<>(child))); items.forEach(modelNodeTreeItem -> fill(modelNodeTreeItem, false, -1)); @@ -275,9 +270,9 @@ public void refresh(@NotNull final Object object) { * @param treeNode the model node */ @FxThread - public void update(@NotNull final TreeNode treeNode) { + public void update(@NotNull TreeNode treeNode) { - final TreeItem> treeItem = findItemForValue(getTreeView(), treeNode); + var treeItem = UiUtils.findItemForValue(getTreeView(), treeNode); if (treeItem == null) { return; } @@ -293,14 +288,14 @@ public void update(@NotNull final TreeNode treeNode) { * @return the context menu. */ @FxThread - public ContextMenu getContextMenu(@Nullable final TreeNode requestedNode) { + public ContextMenu getContextMenu(@Nullable TreeNode requestedNode) { - final C changeConsumer = getChangeConsumer(); + var changeConsumer = getChangeConsumer(); if (changeConsumer == null) { return null; } - final ObservableList>> selectedItems = getTreeView() + var selectedItems = getTreeView() .getSelectionModel() .getSelectedItems(); @@ -308,8 +303,8 @@ public ContextMenu getContextMenu(@Nullable final TreeNode requestedNode) { return null; } - final ContextMenu contextMenu = new ContextMenu(); - final ObservableList items = contextMenu.getItems(); + var contextMenu = new ContextMenu(); + var items = contextMenu.getItems(); if (selectedItems.size() == 1 && requestedNode != null) { @@ -323,11 +318,11 @@ public ContextMenu getContextMenu(@Nullable final TreeNode requestedNode) { } else { - final Array> treeNodes = selectedItems.stream() + var treeNodes = selectedItems.stream() .map(TreeItem::getValue) - .collect(ArrayCollectors.toArray(TreeNode.class)); + .collect(ArrayCollectors.>toArray(TreeNode.class)); - MULTI_ITEMS_ACTION_FILLERS.forEach(filler -> filler.accept(this, items, treeNodes)); + MULTI_ITEMS_ACTION_FILLERS.forEach(filler -> filler.fill(this, items, treeNodes)); } return contextMenu; @@ -342,34 +337,41 @@ public ContextMenu getContextMenu(@Nullable final TreeNode requestedNode) { * @param index the index */ @FxThread - public void notifyMoved(@NotNull final Object prevParent, @NotNull final Object newParent, - @NotNull final Object node, final int index) { - notifyMoved(FACTORY_REGISTRY.createFor(prevParent), FACTORY_REGISTRY.createFor(newParent), - FACTORY_REGISTRY.createFor(node), index); + public void notifyMoved(@NotNull Object prevParent, @NotNull Object newParent, @NotNull Object node, int index) { + notifyMoved( + FACTORY_REGISTRY.createFor(prevParent), + FACTORY_REGISTRY.createFor(newParent), + FACTORY_REGISTRY.createFor(node), + index + ); } /** * Notify about moving the element. */ @FxThread - private void notifyMoved(@Nullable final TreeNode prevParent, @Nullable final TreeNode newParent, - @Nullable final TreeNode node, final int index) { + private void notifyMoved( + @Nullable TreeNode prevParent, + @Nullable TreeNode newParent, + @Nullable TreeNode node, + int index + ) { - final TreeView> treeView = getTreeView(); - final TreeItem> prevParentItem = findItemForValue(treeView, prevParent); - final TreeItem> newParentItem = findItemForValue(treeView, newParent); - final TreeItem> nodeItem = findItemForValue(treeView, node); + var treeView = getTreeView(); + var prevParentItem = UiUtils.findItemForValue(treeView, prevParent); + var newParentItem = UiUtils.findItemForValue(treeView, newParent); + var nodeItem = UiUtils.findItemForValue(treeView, node); if (prevParentItem == null || newParentItem == null || nodeItem == null) { return; } - final TreeNode prevParenTreeNode = prevParentItem.getValue(); + var prevParenTreeNode = prevParentItem.getValue(); prevParenTreeNode.notifyChildPreRemove(node); prevParentItem.getChildren().remove(nodeItem); prevParenTreeNode.notifyChildRemoved(node); - final TreeNode newParentTreeNode = newParentItem.getValue(); + var newParentTreeNode = newParentItem.getValue(); newParentTreeNode.notifyChildAdded(node); if (index >= 0) { @@ -430,7 +432,7 @@ public void notifyReplace(@Nullable final Object parent, @Nullable final Object @Nullable final Object newChild, final boolean needExpand, final boolean needDeepExpand) { final TreeView> treeView = getTreeView(); - final TreeItem> parentItem = findItemForValue(treeView, parent); + final TreeItem> parentItem = UiUtils.findItemForValue(treeView, parent); if (parentItem == null) { if (newChild == null) return; @@ -446,7 +448,7 @@ public void notifyReplace(@Nullable final Object parent, @Nullable final Object final TreeNode parentNode = parentItem.getValue(); final MultipleSelectionModel>> selectionModel = treeView.getSelectionModel(); final ObservableList>> children = parentItem.getChildren(); - final TreeItem> oldChildItem = oldChild == null ? null : findItemForValue(treeView, oldChild); + final TreeItem> oldChildItem = oldChild == null ? null : UiUtils.findItemForValue(treeView, oldChild); final TreeItem> selectedItem = selectionModel.getSelectedItem(); final boolean needSelect = selectedItem == oldChildItem; @@ -492,8 +494,8 @@ public void notifyAdded(@Nullable final Object parent, @Nullable final Object ch } final TreeView> treeView = getTreeView(); - final TreeItem> parentItem = findItemForValue(treeView, parent); - if (parentItem == null || findItemForValue(parentItem, child) != null) { + final TreeItem> parentItem = UiUtils.findItemForValue(treeView, parent); + if (parentItem == null || UiUtils.findItemForValue(parentItem, child) != null) { return; } @@ -561,11 +563,11 @@ public void notifyRemoved(@Nullable final Object parent, @NotNull final Object c final TreeItem> treeItem; if (parent != null) { - final TreeItem> parentItem = findItemForValue(treeView, parent); + final TreeItem> parentItem = UiUtils.findItemForValue(treeView, parent); if (parentItem == null) return null; - treeItem = findItemForValue(parentItem, child); + treeItem = UiUtils.findItemForValue(parentItem, child); } else { - treeItem = findItemForValue(treeView, child); + treeItem = UiUtils.findItemForValue(treeView, child); } return treeItem; @@ -580,7 +582,7 @@ public void notifyRemoved(@Nullable final Object parent, @NotNull final Object c @FxThread public @Nullable TreeNode findParent(@NotNull final TreeNode treeNode) { - final TreeItem> treeItem = findItemForValue(getTreeView(), treeNode); + final TreeItem> treeItem = UiUtils.findItemForValue(getTreeView(), treeNode); if (treeItem == null) { return null; } @@ -598,7 +600,7 @@ public void notifyRemoved(@Nullable final Object parent, @NotNull final Object c public void startEdit(@NotNull final TreeNode treeNode) { final TreeView> treeView = getTreeView(); - final TreeItem> treeItem = findItemForValue(treeView, treeNode); + final TreeItem> treeItem = UiUtils.findItemForValue(treeView, treeNode); if (treeItem == null) { return; } @@ -623,7 +625,7 @@ public void selectSingle(@Nullable final Object object) { } final TreeNode treeNode = FACTORY_REGISTRY.createFor(object); - final TreeItem> treeItem = findItemForValue(treeView, treeNode); + final TreeItem> treeItem = UiUtils.findItemForValue(treeView, treeNode); if (treeItem == null) { selectionModel.clearSelection(); @@ -648,7 +650,7 @@ public void selects(@NotNull final Array objects) { objects.stream().map(FACTORY_REGISTRY::createFor) .filter(Objects::nonNull) - .map(node -> findItemForValue(treeView, node)) + .map(node -> UiUtils.findItemForValue(treeView, node)) .filter(Objects::nonNull) .forEach(selectionModel::select); } @@ -728,4 +730,24 @@ public int getSelectedCount() { public @Nullable C getChangeConsumer() { return changeConsumer; } + + /** + * Require a change consumer. + * + * @return the change consumer. + */ + @FxThread + public @NotNull C requireChangeConsumer() { + return notNull(changeConsumer); + } + + /** + * Get an option of a change consumer. + * + * @return the change consumer. + */ + @FxThread + public @NotNull Optional getChangeConsumerOpt() { + return Optional.ofNullable(changeConsumer); + } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java b/src/main/java/com/ss/builder/fx/control/tree/NodeTreeCell.java similarity index 81% rename from src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java rename to src/main/java/com/ss/builder/fx/control/tree/NodeTreeCell.java index 8f92d8cf..ff79da8f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java +++ b/src/main/java/com/ss/builder/fx/control/tree/NodeTreeCell.java @@ -1,20 +1,29 @@ -package com.ss.editor.ui.control.tree; +package com.ss.builder.fx.control.tree; -import static com.ss.editor.ui.util.UiUtils.findItem; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; +import static com.ss.builder.fx.util.UiUtils.findItem; +import static com.ss.builder.fx.util.UiUtils.findItemForValue; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.HideableNode; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.fx.util.FXUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.HideableNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.HideableNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.fx.util.FxUtils; import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanPropertyBase; import javafx.css.PseudoClass; @@ -40,31 +49,24 @@ */ public class NodeTreeCell> extends TextFieldTreeCell> { - @NotNull public static final DataFormat DATA_FORMAT = new DataFormat(NodeTreeCell.class.getName()); - @NotNull private static final PseudoClass DROP_AVAILABLE_PSEUDO_CLASS = PseudoClass.getPseudoClass("drop-available"); - - @NotNull private static final PseudoClass DRAGGED_PSEUDO_CLASS = PseudoClass.getPseudoClass("dragged"); - - @NotNull private static final PseudoClass EDITING_PSEUDO_CLASS = PseudoClass.getPseudoClass("editing"); - @NotNull private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); @NotNull - private final StringConverter> stringConverter = new StringConverter>() { + private final StringConverter> stringConverter = new StringConverter<>() { @Override - public String toString(@Nullable final TreeNode object) { + public String toString(@Nullable TreeNode object) { return object == null ? "" : object.getName(); } @Override - public TreeNode fromString(@NotNull final String string) { + public TreeNode fromString(@NotNull String string) { final TreeNode item = getItem(); if (item == null) { @@ -82,6 +84,8 @@ public TreeNode fromString(@NotNull final String string) { */ @NotNull private final BooleanProperty dragged = new BooleanPropertyBase(false) { + + @Override public void invalidated() { pseudoClassStateChanged(DRAGGED_PSEUDO_CLASS, get()); } @@ -102,6 +106,8 @@ public String getName() { */ @NotNull private final BooleanProperty dropAvailable = new BooleanPropertyBase(false) { + + @Override public void invalidated() { pseudoClassStateChanged(DROP_AVAILABLE_PSEUDO_CLASS, get()); } @@ -122,6 +128,8 @@ public String getName() { */ @NotNull private final BooleanProperty editing = new BooleanPropertyBase(false) { + + @Override public void invalidated() { pseudoClassStateChanged(EDITING_PSEUDO_CLASS, get()); } @@ -172,7 +180,7 @@ public String getName() { */ private boolean ignoreUpdate; - public NodeTreeCell(@NotNull final M nodeTree) { + public NodeTreeCell(@NotNull M nodeTree) { this.nodeTree = nodeTree; this.icon = new ImageView(); this.content = new HBox(); @@ -182,6 +190,7 @@ public NodeTreeCell(@NotNull final M nodeTree) { this.visibleIcon.setOnMouseReleased(this::processHide); this.visibleIcon.setPickOnBounds(true); + setConverter(stringConverter); setOnMouseClicked(this::processClick); setOnDragDetected(this::startDrag); setOnDragDone(this::stopDrag); @@ -192,14 +201,10 @@ public NodeTreeCell(@NotNull final M nodeTree) { if (isEditing()) event.consume(); }); - FXUtils.addToPane(icon, content); - FXUtils.addToPane(visibleIcon, content); - FXUtils.addToPane(text, content); + FxUtils.addClass(content, CssClasses.DEF_HBOX) + .addClass(this, CssClasses.ABSTRACT_NODE_TREE_CELL); - setConverter(stringConverter); - - FXUtils.addClassTo(content, CssClasses.DEF_HBOX); - FXUtils.addClassTo(this, CssClasses.ABSTRACT_NODE_TREE_CELL); + FxUtils.addChild(content, icon, visibleIcon, text); } /** @@ -228,6 +233,7 @@ private void processHide(@NotNull final MouseEvent event) { @Override @FxThread public void startEdit() { + if (!isEditable()) { return; } @@ -249,6 +255,8 @@ public void startEdit() { } /** + * Return true if need to ignore update. + * * @return true if need to ignore update. */ @FxThread @@ -257,10 +265,12 @@ private boolean isIgnoreUpdate() { } /** - * @param ignoreUpdate the flag of ignoring updates. + * Set true if need to ignore update. + * + * @param ignoreUpdate true if need to ignore update. */ @FxThread - private void setIgnoreUpdate(final boolean ignoreUpdate) { + private void setIgnoreUpdate(boolean ignoreUpdate) { this.ignoreUpdate = ignoreUpdate; } @@ -313,11 +323,15 @@ public void updateItem(@Nullable final TreeNode item, final boolean empty) { return; } - final ImageView icon = getIcon(); + var icon = getIcon(); if (item == null) { - final TreeItem> treeItem = getTreeItem(); - if (treeItem != null) treeItem.setGraphic(null); + + var treeItem = getTreeItem(); + if (treeItem != null) { + treeItem.setGraphic(null); + } + setText(StringUtils.EMPTY); setEditable(false); return; @@ -327,8 +341,10 @@ public void updateItem(@Nullable final TreeNode item, final boolean empty) { DynamicIconSupport.updateListener(this, icon, selectedProperty()); - final TreeItem> treeItem = getTreeItem(); - if (treeItem != null) treeItem.setGraphic(content); + var treeItem = getTreeItem(); + if (treeItem != null) { + treeItem.setGraphic(content); + } HideableNode hideable = null; @@ -367,32 +383,32 @@ public void updateItem(@Nullable final TreeNode item, final boolean empty) { * Handle a mouse click. */ @FxThread - private void processClick(@NotNull final MouseEvent event) { + private void processClick(@NotNull MouseEvent event) { - final TreeNode item = getItem(); + var item = getItem(); if (item == null) { return; } - final MouseButton button = event.getButton(); + var button = event.getButton(); if (button != MouseButton.SECONDARY) { return; } - final M nodeTree = getNodeTree(); - final ContextMenu contextMenu = nodeTree.getContextMenu(item); + var contextMenu = getNodeTree().getContextMenu(item); if (contextMenu == null) { return; } - EXECUTOR_MANAGER.addFxTask(() -> contextMenu.show(this, Side.BOTTOM, 0, 0)); + EXECUTOR_MANAGER.addFxTask(() -> + contextMenu.show(this, Side.BOTTOM, 0, 0)); } /** * Handle stopping dragging. */ @FxThread - private void stopDrag(@NotNull final DragEvent event) { + private void stopDrag(@NotNull DragEvent event) { dragged.setValue(false); setCursor(Cursor.DEFAULT); event.consume(); @@ -402,7 +418,7 @@ private void stopDrag(@NotNull final DragEvent event) { * Handle starting dragging. */ @FxThread - private void startDrag(@NotNull final MouseEvent mouseEvent) { + private void startDrag(@NotNull MouseEvent mouseEvent) { final TreeNode item = getItem(); if (item == null) { @@ -410,7 +426,7 @@ private void startDrag(@NotNull final MouseEvent mouseEvent) { } final TreeView> treeView = getTreeView(); - final TreeItem> treeItem = findItemForValue(treeView, item); + final TreeItem> treeItem = UiUtils.findItemForValue(treeView, item); if (treeView.getRoot() == treeItem) { return; } @@ -456,13 +472,13 @@ private void dragDropped(@NotNull final DragEvent dragEvent) { if (objectId != null) { final TreeView> treeView = getTreeView(); - final TreeItem> dragTreeItem = findItem(treeView, objectId); + final TreeItem> dragTreeItem = UiUtils.findItem(treeView, objectId); final TreeNode dragItem = dragTreeItem == null ? null : dragTreeItem.getValue(); if (dragItem == null || !item.canAccept(dragItem, isCopy)) { return; } - final TreeItem> newParentItem = findItemForValue(treeView, item); + final TreeItem> newParentItem = UiUtils.findItemForValue(treeView, item); if (newParentItem == null) { return; } @@ -496,7 +512,7 @@ private void dragOver(@NotNull final DragEvent dragEvent) { if (objectId != null) { final TreeView> treeView = getTreeView(); - final TreeItem> dragTreeItem = findItem(treeView, objectId); + final TreeItem> dragTreeItem = UiUtils.findItem(treeView, objectId); final TreeNode dragItem = dragTreeItem == null ? null : dragTreeItem.getValue(); if (dragItem == null || !item.canAccept(dragItem, isCopy)) return; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/AbstractNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/AbstractNodeAction.java new file mode 100644 index 00000000..3d0fdd57 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/AbstractNodeAction.java @@ -0,0 +1,160 @@ +package com.ss.builder.fx.control.tree.action; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of an action for an element in a node tree. + * + * @param the change consumer's type. + * @author JavaSaBr + */ +public abstract class AbstractNodeAction extends MenuItem implements Comparable { + + protected static final Logger LOGGER = LoggerManager.getLogger(AbstractNodeAction.class); + + @FunctionalInterface + public interface AdditionalAction { + + @Nullable Runnable makeAction(@NotNull T object); + } + + /** + * The component of the node tree. + */ + @NotNull + private final NodeTree nodeTree; + + /** + * The node. + */ + @NotNull + private final TreeNode node; + + /** + * The nodes. + */ + @NotNull + private final Array> nodes; + + public AbstractNodeAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + this(nodeTree, node, Array.empty()); + } + + public AbstractNodeAction(@NotNull NodeTree nodeTree, @NotNull Array> nodes) { + this(nodeTree, notNull(nodes.first()), nodes); + } + + AbstractNodeAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node, @NotNull Array> nodes) { + this.nodeTree = unsafeCast(nodeTree); + this.node = node; + this.nodes = nodes; + + setOnAction(event -> process()); + setText(getName()); + + var icon = getIcon(); + + if (icon != null) { + setGraphic(new ImageView(icon)); + } + } + + /** + * Get the action's name. + * + * @return the action's name. + */ + @FxThread + protected abstract @NotNull String getName(); + + /** + * Execute this action. + */ + @FxThread + protected void process() { + GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EXECUTE_NODE_ACTION, getClass().getSimpleName()); + } + + /** + * The icon of this action. + * + * @return the icon or null. + */ + @FxThread + protected @Nullable Image getIcon() { + return null; + } + + /** + * Get the node tree. + * + * @return the component of the model three. + */ + @FxThread + protected @NotNull NodeTree getNodeTree() { + return nodeTree; + } + + /** + * Get the node. + * + * @return the node. + */ + @FxThread + protected @NotNull TreeNode getNode() { + return node; + } + + /** + * Get the nodes. + * + * @return the nodes. + */ + @FxThread + protected @NotNull Array> getNodes() { + return nodes; + } + + /** + * Get the order. + * + * @return the order. + */ + @FxThread + protected int getOrder() { + return 0; + } + + @Override + public int compareTo(@NotNull MenuItem item) { + if (!(item instanceof AbstractNodeAction)) { + return 0; + } else { + return ((AbstractNodeAction) item).getOrder() - getOrder(); + } + } + + @Override + public String toString() { + return "AbstractNodeAction{name = " + getNode() + "} " + super.toString(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/AddUserDataAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/AddUserDataAction.java similarity index 80% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/AddUserDataAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/AddUserDataAction.java index 45c7cb23..57c166a1 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/AddUserDataAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/AddUserDataAction.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl; +package com.ss.builder.fx.control.tree.action.impl; import static com.ss.editor.extension.property.EditablePropertyType.ENUM; import static com.ss.editor.extension.property.EditablePropertyType.STRING; @@ -7,17 +7,24 @@ import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.operation.PropertyCountOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyCountOperation; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyCountOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/CopyNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CopyNodeAction.java new file mode 100644 index 00000000..cce59c99 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CopyNodeAction.java @@ -0,0 +1,57 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.builder.fx.control.tree.NodeTreeCell.DATA_FORMAT; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to copy a node in model. + * + * @author JavaSaBr + */ +public class CopyNodeAction extends AbstractNodeAction { + + public CopyNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_COPY; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.COPY_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + + final ClipboardContent content = new ClipboardContent(); + content.put(DATA_FORMAT, node.getObjectId()); + + final Clipboard clipboard = Clipboard.getSystemClipboard(); + clipboard.setContent(content); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateEditableSkyAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateEditableSkyAction.java new file mode 100644 index 00000000..d8d13d51 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateEditableSkyAction.java @@ -0,0 +1,37 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.dialog.sky.CreateEditableSkyDialog; +import com.ss.builder.fx.dialog.sky.CreateSkyDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.dialog.sky.CreateEditableSkyDialog; +import com.ss.builder.fx.dialog.sky.CreateSkyDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create SS sky. + * + * @author JavaSaBr + */ +public class CreateEditableSkyAction extends CreateSkyAction { + + public CreateEditableSkyAction(final @NotNull NodeTree nodeTree, final @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_EDITABLE_SKY; + } + + @Override + @FxThread + protected @NotNull CreateSkyDialog createDialog() { + return new CreateEditableSkyDialog(getNode(), getNodeTree()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateNodeAction.java new file mode 100644 index 00000000..12e08b8f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateNodeAction.java @@ -0,0 +1,70 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.builder.util.EditorUtils.getDefaultLayer; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a node. + * + * @author JavaSaBr + */ +public class CreateNodeAction extends AbstractNodeAction { + + public CreateNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.NODE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_NODE; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final Node node = new Node("New Node"); + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + + final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + final SceneLayer defaultLayer = EditorUtils.getDefaultLayer(consumer); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, node); + } + + consumer.execute(new AddChildOperation(node, parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateSkyAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateSkyAction.java new file mode 100644 index 00000000..0e49ea0d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/CreateSkyAction.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.sky.CreateSkyDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.sky.CreateSkyDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create sky. + * + * @author JavaSaBr + */ +public class CreateSkyAction extends AbstractNodeAction { + + public CreateSkyAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.SKY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_SKY; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final CreateSkyDialog dialog = createDialog(); + dialog.show(); + } + + @FxThread + protected @NotNull CreateSkyDialog createDialog() { + return new CreateSkyDialog(getNode(), getNodeTree()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/DisableAllControlsAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/DisableAllControlsAction.java new file mode 100644 index 00000000..b0067099 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/DisableAllControlsAction.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.DisableControlsOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.DisableControlsOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to disable all controls in a selected node. + * + * @author JavaSaBr + */ +public class DisableAllControlsAction extends AbstractNodeAction { + + public DisableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.STOP_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_DISABLE_ALL_CONTROLS; + } + + @Override + @FxThread + protected void process() { + + final Array controls = NodeUtils.children((Spatial) getNode().getElement()) + .flatMap(ControlUtils::controls) + .filter(ControlUtils::isEnabled) + .collect(toArray(Control.class)); + + final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(new DisableControlsOperation(controls)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/EnableAllControlsAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/EnableAllControlsAction.java new file mode 100644 index 00000000..ac3b164b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/EnableAllControlsAction.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.EnableControlsOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.EnableControlsOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to enable all controls in a selected node. + * + * @author JavaSaBr + */ +public class EnableAllControlsAction extends AbstractNodeAction { + + public EnableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PLAY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ENABLE_ALL_CONTROLS; + } + + @Override + @FxThread + protected void process() { + + final Array controls = NodeUtils.children((Spatial) getNode().getElement()) + .flatMap(ControlUtils::controls) + .filter(control -> !ControlUtils.isEnabled(control)) + .collect(toArray(Control.class)); + + final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(new EnableControlsOperation(controls)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/LinkModelAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/LinkModelAction.java new file mode 100644 index 00000000..86f2896a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/LinkModelAction.java @@ -0,0 +1,124 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_LOADED_MODEL; +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.builder.util.EditorUtils.toAssetPath; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetManager; +import com.jme3.asset.ModelKey; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The implementation of the {@link AbstractNodeAction} for loading the {@link Spatial} to the editor. + * + * @author vp -byte + */ +public class LinkModelAction extends AbstractNodeAction { + + @NotNull + private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || + type == DeleteFileAction.class || + type == RenameFileAction.class; + + @NotNull + private static final Array MODEL_EXTENSIONS = ArrayFactory.newArray(String.class); + + static { + MODEL_EXTENSIONS.add(FileExtensions.JME_OBJECT); + } + + public LinkModelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.LINK_FILE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_LINK_MODEL; + } + + @FxThread + @Override + protected void process() { + super.process(); + UiUtils.openFileAssetDialog(this::processOpen, MODEL_EXTENSIONS, ACTION_TESTER); + } + + /** + * The process of opening file. + * + * @param file the file + */ + @FxThread + protected void processOpen(@NotNull final Path file) { + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + final SceneLayer defaultLayer = EditorUtils.getDefaultLayer(consumer); + + final Path assetFile = notNull(EditorUtils.getAssetFile(file), "Not found asset file for " + file); + final String assetPath = EditorUtils.toAssetPath(assetFile); + + final ModelKey modelKey = new ModelKey(assetPath); + + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Spatial loadedModel = assetManager.loadModel(modelKey); + + final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); + assetLinkNode.attachLinkedChild(loadedModel, modelKey); + assetLinkNode.setUserData(AbstractSceneEditor3dPart.KEY_LOADED_MODEL, true); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, assetLinkNode); + } + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + consumer.execute(new AddChildOperation(assetLinkNode, parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/LoadModelAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/LoadModelAction.java new file mode 100644 index 00000000..55bdf8ff --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/LoadModelAction.java @@ -0,0 +1,119 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_LOADED_MODEL; +import static com.ss.builder.util.EditorUtils.*; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetManager; +import com.jme3.asset.ModelKey; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The implementation of the {@link AbstractNodeAction} for loading the {@link Spatial} to the editor. + * + * @author JavaSaBr + */ +public class LoadModelAction extends AbstractNodeAction { + + @NotNull + private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || + type == DeleteFileAction.class || + type == RenameFileAction.class; + + @NotNull + private static final Array MODEL_EXTENSIONS = ArrayFactory.newArray(String.class); + + static { + MODEL_EXTENSIONS.add(FileExtensions.JME_OBJECT); + } + + public LoadModelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.OPEN_FILE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_LOAD_MODEL; + } + + @Override + @FxThread + protected void process() { + super.process(); + UiUtils.openFileAssetDialog(this::processOpen, MODEL_EXTENSIONS, ACTION_TESTER); + } + + /** + * The process of opening file. + * + * @param file the file + */ + @FxThread + protected void processOpen(@NotNull final Path file) { + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + final SceneLayer defaultLayer = EditorUtils.getDefaultLayer(consumer); + + final Path assetFile = notNull(EditorUtils.getAssetFile(file), "Not found asset file for " + file); + final String assetPath = EditorUtils.toAssetPath(assetFile); + + final ModelKey modelKey = new ModelKey(assetPath); + + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Spatial loadedModel = assetManager.loadModel(modelKey); + loadedModel.setUserData(AbstractSceneEditor3dPart.KEY_LOADED_MODEL, true); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, loadedModel); + } + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + consumer.execute(new AddChildOperation(loadedModel, parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java new file mode 100644 index 00000000..755e6b37 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java @@ -0,0 +1,61 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetKey; +import com.jme3.material.Material; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link AbstractNodeAction} to make a material as embedded. + * + * @author JavaSaBr + */ +public class MakeAsEmbeddedMaterialAction extends AbstractNodeAction { + + public MakeAsEmbeddedMaterialAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.INFLUENCER_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_MAKE_EMBEDDED; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + final Material material = (Material) node.getElement(); + + final PropertyOperation operation = + new PropertyOperation<>(material, "AssetKey", null, material.getKey()); + operation.setApplyHandler(Material::setKey); + + final ChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(operation); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/OptimizeGeometryAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/OptimizeGeometryAction.java new file mode 100644 index 00000000..21af764f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/OptimizeGeometryAction.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.OptimizeGeometryOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.OptimizeGeometryOperation; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import jme3tools.optimize.GeometryBatchFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to optimize a geometry. + * + * @author JavaSaBr + */ +public class OptimizeGeometryAction extends AbstractNodeAction { + + public OptimizeGeometryAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.INFLUENCER_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_OPTIMIZE_GEOMETRY; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final TreeNode node = getNode(); + final Node oldElement = (Node) node.getElement(); + final Node newElement = (Node) oldElement.clone(); + + GeometryBatchFactory.optimize(newElement); + + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new OptimizeGeometryOperation(newElement, oldElement, oldElement.getParent())); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/PasteNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/PasteNodeAction.java new file mode 100644 index 00000000..a2f97174 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/PasteNodeAction.java @@ -0,0 +1,58 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to paste a node in model. + * + * @author JavaSaBr + */ +public class PasteNodeAction extends AbstractNodeAction { + + /** + * The copied node. + */ + @NotNull + private final TreeNode copiedNode; + + public PasteNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node, + @NotNull final TreeNode copiedNode) { + super(nodeTree, node); + this.copiedNode = copiedNode; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_PASTE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PASTE_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + final TreeNode node = getNode(); + node.accept(changeConsumer, copiedNode.getElement(), true); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveControlAction.java new file mode 100644 index 00000000..442d8a9d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveControlAction.java @@ -0,0 +1,72 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveControlOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.RemoveControlOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The implementation of the {@link AbstractNodeAction} to remove a control from a {@link Spatial}. + * + * @author JavaSaBr + */ +public class RemoveControlAction extends AbstractNodeAction { + + public RemoveControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + final Object element = node.getElement(); + + if (!(element instanceof Control)) return; + final Control control = (Control) element; + + final TreeNode parentNode = node.getParent(); + + if (parentNode == null) { + LOGGER.warning("not found parent node for " + node); + return; + } + + final Object parent = parentNode.getElement(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveControlOperation(control, (Spatial) parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveLightAction.java new file mode 100644 index 00000000..9607e0c9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveLightAction.java @@ -0,0 +1,70 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveLightOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.RemoveLightOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to remove a light. + * + * @author JavaSaBr + */ +public class RemoveLightAction extends AbstractNodeAction { + + public RemoveLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + final Object element = node.getElement(); + + if (!(element instanceof Light)) return; + + final Light light = (Light) element; + + final NodeTree nodeTree = getNodeTree(); + final TreeNode parentNode = nodeTree.findParent(node); + if (parentNode == null) return; + + final Object parent = parentNode.getElement(); + if (!(parent instanceof Node)) return; + + final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveLightOperation(light, (Node) parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveNodeAction.java new file mode 100644 index 00000000..cdae440f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RemoveNodeAction.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.RemoveChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to remove a node from model. + * + * @author JavaSaBr + */ +public class RemoveNodeAction extends AbstractNodeAction { + + public RemoveNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + final Object element = node.getElement(); + if (!(element instanceof Spatial)) { + return; + } + + final Spatial spatial = (Spatial) element; + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveChildOperation(spatial, spatial.getParent())); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/RenameNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RenameNodeAction.java new file mode 100644 index 00000000..8a3a5837 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/RenameNodeAction.java @@ -0,0 +1,48 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to rename a model node. + * + * @author JavaSaBr + */ +public class RenameNodeAction extends AbstractNodeAction { + + public RenameNodeAction(@NotNull final NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.EDIT_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_RENAME; + } + + @Override + @FxThread + protected void process() { + super.process(); + final NodeTree nodeTree = getNodeTree(); + nodeTree.startEdit(getNode()); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/SaveAsMaterialAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/SaveAsMaterialAction.java new file mode 100644 index 00000000..79e9925b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/SaveAsMaterialAction.java @@ -0,0 +1,112 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.builder.util.EditorUtils.toAssetPath; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.nio.file.StandardOpenOption.*; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.component.asset.tree.context.menu.action.DeleteFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.component.asset.tree.context.menu.action.RenameFileAction; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The implementation of the {@link AbstractNodeAction} to save a material as file. + * + * @author JavaSaBr + */ +public class SaveAsMaterialAction extends AbstractNodeAction { + + @NotNull + private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || + type == DeleteFileAction.class || + type == RenameFileAction.class; + + public SaveAsMaterialAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.SAVE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_SAVE_AS; + } + + @Override + @FxThread + protected void process() { + super.process(); + UiUtils.openSaveAsDialog(this::processSave, FileExtensions.JME_MATERIAL, ACTION_TESTER); + } + + /** + * The process of saving the file. + * + * @param file the file to save + */ + @FxThread + private void processSave(@NotNull final Path file) { + + final TreeNode node = getNode(); + final Material material = (Material) node.getElement(); + final String materialContent = MaterialSerializer.serializeToString(material); + + try (final PrintWriter out = new PrintWriter(Files.newOutputStream(file, WRITE, TRUNCATE_EXISTING, CREATE))) { + out.print(materialContent); + } catch (final IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return; + } + + final Path assetFile = notNull(EditorUtils.getAssetFile(file)); + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Material savedMaterial = assetManager.loadMaterial(notNull(EditorUtils.toAssetPath(assetFile))); + + final PropertyOperation operation = + new PropertyOperation<>(material, "AssetKey", savedMaterial.getKey(), null); + operation.setApplyHandler(Material::setKey); + + final ChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(operation); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/TangentGeneratorAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/TangentGeneratorAction.java new file mode 100644 index 00000000..6fa37ae9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/TangentGeneratorAction.java @@ -0,0 +1,50 @@ +package com.ss.builder.fx.control.tree.action.impl; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.GenerateTangentsDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.GenerateTangentsDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action for generating tangents. + * + * @author JavaSaBr + */ +public class TangentGeneratorAction extends AbstractNodeAction { + + public TangentGeneratorAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_TANGENT_GENERATOR; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + final GenerateTangentsDialog dialog = new GenerateTangentsDialog(getNodeTree(), getNode()); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java new file mode 100644 index 00000000..16675512 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.dialog.animation.ExtractSubAnimationDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to manual extract a sub-animation from an animation. + * + * @author JavaSaBr + */ +public class ManualExtractSubAnimationAction extends AbstractNodeAction { + + public ManualExtractSubAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_MANUAL_EXTRACT_SUB_ANIMATION; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.EXTRACT_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + final NodeTree nodeTree = getNodeTree(); + final ExtractSubAnimationDialog dialog = new ExtractSubAnimationDialog(nodeTree, (AnimationTreeNode) getNode()); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PauseAnimationAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PauseAnimationAction.java new file mode 100644 index 00000000..ea80609b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PauseAnimationAction.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to pause an animation. + * + * @author JavaSaBr + */ +public class PauseAnimationAction extends AbstractNodeAction { + + public PauseAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PAUSE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PAUSE_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final AnimationTreeNode modelNode = (AnimationTreeNode) getNode(); + if (modelNode.getChannel() < 0) return; + + final AnimControl control = modelNode.getControl(); + if (control == null || control.getNumChannels() <= 0) return; + + final AnimChannel channel = control.getChannel(modelNode.getChannel()); + channel.setSpeed(0); + modelNode.setSpeed(0); + + final NodeTree nodeTree = getNodeTree(); + nodeTree.update(modelNode); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlayAnimationAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlayAnimationAction.java new file mode 100644 index 00000000..a37135df --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlayAnimationAction.java @@ -0,0 +1,120 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.LoopMode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to play an animation. + * + * @author JavaSaBr + */ +public class PlayAnimationAction extends AbstractNodeAction implements AnimEventListener { + + public PlayAnimationAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PLAY; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PLAY_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + var modelNode = (AnimationTreeNode) getNode(); + var controlModelNode = modelNode.getControlModelNode(); + + if (controlModelNode == null) { + return; + } + + var element = modelNode.getElement(); + var control = modelNode.getControl(); + + if (control == null) { + return; + } + + modelNode.setSpeed(controlModelNode.getSpeed()); + + if (modelNode.getChannel() >= 0) { + var channel = control.getChannel(modelNode.getChannel()); + channel.setSpeed(controlModelNode.getSpeed()); + } else { + + modelNode.setChannel(control.getNumChannels()); + + ExecutorManager.getInstance().addJmeTask(() -> { + control.addListener(this); + + var channel = control.createChannel(); + channel.setAnim(element.getName()); + channel.setLoopMode(controlModelNode.getLoopMode()); + channel.setSpeed(controlModelNode.getSpeed()); + }); + } + + getNodeTree().update(modelNode); + } + + @Override + @JmeThread + public void onAnimCycleDone(@NotNull AnimControl control, @NotNull AnimChannel channel, @NotNull String animName) { + + if (channel.getLoopMode() != LoopMode.DontLoop) { + return; + } + + var modelNode = (AnimationTreeNode) getNode(); + var element = modelNode.getElement(); + + if (!StringUtils.equals(element.getName(), animName)) { + return; + } + + modelNode.setChannel(-1); + + ExecutorManager.getInstance() + .addFxTask(() -> getNodeTree().update(modelNode)); + + ExecutorManager.getInstance() + .addJmeTask(control::clearChannels); + } + + @Override + @JmeThread + public void onAnimChange(@NotNull AnimControl control, @NotNull AnimChannel channel, @NotNull String animName) { + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlaySettingsAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlaySettingsAction.java new file mode 100644 index 00000000..615153a1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/PlaySettingsAction.java @@ -0,0 +1,76 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import static com.ss.editor.extension.property.EditablePropertyType.ENUM; +import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; +import com.jme3.animation.LoopMode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationControlTreeNode; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to open play settings of an animation. + * + * @author JavaSaBr + */ +public class PlaySettingsAction extends AbstractNodeAction { + + @NotNull + private static final String PROPERTY_LOOP_MODE = "loopMode"; + + @NotNull + private static final String PROPERTY_SPEED = "speed"; + + public PlaySettingsAction(@NotNull final NodeTree nodeTree, @NotNull final AnimationControlTreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PLAY_SETTINGS; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.SETTINGS_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final AnimationControlTreeNode node = (AnimationControlTreeNode) getNode(); + final LoopMode loopMode = node.getLoopMode(); + final float speed = node.getSpeed(); + + final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); + definitions.add(new PropertyDefinition(ENUM, Messages.MODEL_PROPERTY_LOOP_MODE, PROPERTY_LOOP_MODE, loopMode)); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_SPEED, PROPERTY_SPEED, speed)); + + final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, vars -> + node.updateSettings(vars.get(PROPERTY_LOOP_MODE), vars.get(PROPERTY_SPEED))); + + dialog.setTitle(Messages.PLAY_ANIMATION_SETTINGS_DIALOG_TITLE); + dialog.setButtonOkText(Messages.SIMPLE_DIALOG_BUTTON_OK); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/RemoveAnimationAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/RemoveAnimationAction.java new file mode 100644 index 00000000..f4c8a705 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/RemoveAnimationAction.java @@ -0,0 +1,70 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.animation.RemoveAnimationNodeOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.animation.RemoveAnimationNodeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link AbstractNodeAction} to remove an animation from the {@link AnimControl}. + * + * @author JavaSaBr + */ +public class RemoveAnimationAction extends AbstractNodeAction { + + public RemoveAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final TreeNode node = getNode(); + final Object element = node.getElement(); + + if (!(element instanceof Animation)) return; + final Animation animation = (Animation) element; + + final NodeTree nodeTree = getNodeTree(); + final TreeNode parentNode = nodeTree.findParent(node); + + if (parentNode == null) { + LOGGER.warning("not found parent node for " + node); + return; + } + + final AnimControl parent = (AnimControl) parentNode.getElement(); + + final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveAnimationNodeOperation(animation, parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/StopAnimationAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/StopAnimationAction.java new file mode 100644 index 00000000..ebc4dd5a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/animation/StopAnimationAction.java @@ -0,0 +1,68 @@ +package com.ss.builder.fx.control.tree.action.impl.animation; + +import com.jme3.animation.LoopMode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to stop an animation. + * + * @author JavaSaBr + */ +public class StopAnimationAction extends AbstractNodeAction { + + public StopAnimationAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_STOP; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.STOP_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + var modelNode = (AnimationTreeNode) getNode(); + if (modelNode.getChannel() < 0) { + return; + } + + var control = modelNode.getControl(); + if (control == null || control.getNumChannels() <= 0) { + return; + } + + var channel = control.getChannel(modelNode.getChannel()); + channel.setLoopMode(LoopMode.DontLoop); + + ExecutorManager.getInstance() + .addJmeTask(control::clearChannels); + + getNodeTree().update(modelNode); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/CreateAudioNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/CreateAudioNodeAction.java new file mode 100644 index 00000000..5c6629ce --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/CreateAudioNodeAction.java @@ -0,0 +1,66 @@ +package com.ss.builder.fx.control.tree.action.impl.audio; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.audio.AudioNode; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create an audio node. + * + * @author JavaSaBr + */ +public class CreateAudioNodeAction extends AbstractNodeAction { + + public CreateAudioNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.AUDIO_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_AUDIO_NODE; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + + final AudioNode node = new AudioNode(); + node.setName("New audio"); + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new AddChildOperation(node, parent)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/PlayAudioNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/PlayAudioNodeAction.java new file mode 100644 index 00000000..a2b136be --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/PlayAudioNodeAction.java @@ -0,0 +1,72 @@ +package com.ss.builder.fx.control.tree.action.impl.audio; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.AudioNodeUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.AudioTreeNode; +import com.ss.builder.util.AudioNodeUtils; +import com.ss.builder.util.EditorUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to play an audio node. + * + * @author JavaSaBr + */ +public class PlayAudioNodeAction extends AbstractNodeAction { + + public PlayAudioNodeAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PLAY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_AUDIO_PLAY; + } + + @Override + @FxThread + protected void process() { + super.process(); + + ExecutorManager.getInstance() + .addJmeTask(this::play); + } + + @JmeThread + private void play() { + + var audioModelNode = (AudioTreeNode) getNode(); + var audioNode = audioModelNode.getElement(); + var audioKey = AudioNodeUtils.getAudioKey(audioNode); + var audioData = EditorUtils.getAssetManager() + .loadAudio(audioKey); + + AudioNodeUtils.updateData(audioNode, audioData, audioKey); + + audioNode.play(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/StopAudioNodeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/StopAudioNodeAction.java new file mode 100644 index 00000000..13d1ab71 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/audio/StopAudioNodeAction.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.control.tree.action.impl.audio; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.AudioTreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to stop an audio node. + * + * @author JavaSaBr + */ +public class StopAudioNodeAction extends AbstractNodeAction { + + public StopAudioNodeAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.STOP_16; + } + + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_AUDIO_STOP; + } + + @Override + @FxThread + protected void process() { + super.process(); + + var audioModelNode = (AudioTreeNode) getNode(); + var audioNode = audioModelNode.getElement(); + + ExecutorManager.getInstance() + .addJmeTask(audioNode::stop); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/AbstractCreateControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/AbstractCreateControlAction.java new file mode 100644 index 00000000..218ca413 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/AbstractCreateControlAction.java @@ -0,0 +1,67 @@ +package com.ss.builder.fx.control.tree.action.impl.control; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create the {@link Control}. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateControlAction extends AbstractNodeAction { + + public AbstractCreateControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected void process() { + super.process(); + + if (isRequiredDialog()) { + return; + } + + final TreeNode treeNode = getNode(); + final Spatial parent = (Spatial) treeNode.getElement(); + + final NodeTree nodeTree = getNodeTree(); + final Control control = createControl(parent); + + final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + consumer.execute(new AddControlOperation(control, parent)); + } + + /** + * Return true if need a dialog to create a control. + * + * @return true if need a dialog to create a control. + */ + @FxThread + protected boolean isRequiredDialog() { + return false; + } + + /** + * Create a control. + * + * @param parent the parent. + * @return the control. + */ + @FxThread + protected @NotNull Control createControl(@NotNull final Spatial parent) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateCustomControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateCustomControlAction.java new file mode 100644 index 00000000..a539ab77 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateCustomControlAction.java @@ -0,0 +1,68 @@ +package com.ss.builder.fx.control.tree.action.impl.control; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.dialog.CreateCustomControlDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.dialog.CreateCustomControlDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link Control}. + * + * @author JavaSaBr + */ +public class CreateCustomControlAction extends AbstractNodeAction { + + /** + * Instantiates a new Create custom control action. + * + * @param nodeTree the node tree + * @param node the node + */ + public CreateCustomControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @FxThread + @Nullable + @Override + protected Image getIcon() { + return Icons.GEAR_16; + } + + @FxThread + @NotNull + @Override + protected String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_CUSTOM; + } + + @FxThread + @Override + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + + final TreeNode treeNode = getNode(); + final Spatial parent = (Spatial) treeNode.getElement(); + + final CreateCustomControlDialog dialog = new CreateCustomControlDialog(consumer, parent); + dialog.show(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateLightControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateLightControlAction.java new file mode 100644 index 00000000..eecd8748 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateLightControlAction.java @@ -0,0 +1,46 @@ +package com.ss.builder.fx.control.tree.action.impl.control; + +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.jme3.scene.control.LightControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link com.jme3.scene.control.LightControl}. + * + * @author JavaSaBr + */ +public class CreateLightControlAction extends AbstractCreateControlAction { + + public CreateLightControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.LIGHT_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_LIGHT; + } + + @Override + @FxThread + protected @NotNull Control createControl(@NotNull final Spatial parent) { + return new LightControl(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateMotionControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateMotionControlAction.java similarity index 79% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateMotionControlAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateMotionControlAction.java index a88aa21d..c66737af 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateMotionControlAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/CreateMotionControlAction.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.control; +package com.ss.builder.fx.control.tree.action.impl.control; import com.jme3.cinematic.MotionPath; import com.jme3.cinematic.events.MotionEvent; @@ -6,11 +6,14 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateCharacterControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateCharacterControlAction.java new file mode 100644 index 00000000..1aec11eb --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateCharacterControlAction.java @@ -0,0 +1,82 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics; + +import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.bullet.control.BetterCharacterControl; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.control.AbstractCreateControlAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link CharacterControl}. + * + * @author JavaSaBr + */ +public class CreateCharacterControlAction extends AbstractCreateControlAction { + + private static final String PROPERTY_RADIUS = "radius"; + private static final String PROPERTY_HEIGHT = "height"; + private static final String PROPERTY_MASS = "mass"; + + public CreateCharacterControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.CHARACTER_16; + } + + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_CHARACTER; + } + + @Override + protected void process() { + + final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_RADIUS, PROPERTY_RADIUS, 1F)); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_HEIGHT, PROPERTY_HEIGHT, 1F)); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_MASS, PROPERTY_MASS, 1F)); + + final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, vars -> { + + final float radius = vars.getFloat(PROPERTY_RADIUS); + final float height = vars.getFloat(PROPERTY_HEIGHT); + final float mass = vars.getFloat(PROPERTY_MASS); + + final TreeNode treeNode = getNode(); + final Spatial parent = (Spatial) treeNode.getElement(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + consumer.execute(new AddControlOperation(new BetterCharacterControl(radius, height, mass), parent)); + }); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java new file mode 100644 index 00000000..1270a83c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics; + +import com.jme3.bullet.control.KinematicRagdollControl; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.AbstractCreateControlAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link KinematicRagdollControl}. + * + * @author JavaSaBr + */ +public class CreateKinematicRagdollControlAction extends AbstractCreateControlAction { + + public CreateKinematicRagdollControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @FxThread + @Override + protected @Nullable Image getIcon() { + return Icons.ATOM_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_KINEMATIC_RAGDOLL; + } + + @Override + @FxThread + protected @NotNull Control createControl(@NotNull final Spatial parent) { + return new KinematicRagdollControl(0.5F); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java new file mode 100644 index 00000000..dbefc0de --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics; + +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.AbstractCreateControlAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.ControlUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link RigidBodyControl}. + * + * @author JavaSaBr + */ +public class CreateRigidBodyControlAction extends AbstractCreateControlAction { + + public CreateRigidBodyControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.RIGID_BODY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_RIGID_BODY; + } + + @Override + @FxThread + protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { + final RigidBodyControl rigidBodyControl = new RigidBodyControl(); + rigidBodyControl.setEnabled(false); + ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); + return rigidBodyControl; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java new file mode 100644 index 00000000..bd9fbf61 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java @@ -0,0 +1,52 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics; + +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.ControlUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link RigidBodyControl}. + * + * @author JavaSaBr + */ +public class CreateStaticRigidBodyControlAction extends CreateRigidBodyControlAction { + + public CreateStaticRigidBodyControlAction(@NotNull final NodeTree nodeTree, + @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.STATIC_RIGID_BODY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_STATIC_RIGID_BODY; + } + + @Override + @FxThread + protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { + final RigidBodyControl rigidBodyControl = new RigidBodyControl(); + rigidBodyControl.setEnabled(false); + rigidBodyControl.setMass(0F); + ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); + return rigidBodyControl; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java new file mode 100644 index 00000000..3c9bcc0c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java @@ -0,0 +1,57 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics; + +import com.jme3.bullet.control.RigidBodyControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to re-activate a physics control. + * + * @author JavaSaBr + */ +public class ReactivatePhysicsControlAction extends AbstractNodeAction { + + public ReactivatePhysicsControlAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REPLAY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REACTIVATE; + } + + @Override + @FxThread + protected void process() { + + var element = getNode() + .getElement(); + + if (element instanceof RigidBodyControl) { + var control = (RigidBodyControl) element; + ExecutorManager.getInstance() + .addJmeTask(control::activate); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java new file mode 100644 index 00000000..ee80b090 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java @@ -0,0 +1,49 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle; + +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.AbstractCreateControlAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link VehicleControl}. + * + * @author JavaSaBr + */ +public class CreateVehicleControlAction extends AbstractCreateControlAction { + + public CreateVehicleControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.VEHICLE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_VEHICLE; + } + + @Override + @FxThread + protected @NotNull Control createControl(@NotNull final Spatial parent) { + return new VehicleControl(new BoxCollisionShape(new Vector3f(1F, 1F, 1F)), 1F); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java similarity index 77% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java index b83e8673..b0032f43 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java @@ -1,21 +1,29 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle; +package com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle; import static com.ss.editor.extension.property.EditablePropertyType.*; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.bullet.control.VehicleControl; import com.jme3.bullet.objects.VehicleWheel; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.AddVehicleWheelOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddVehicleWheelOperation; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.AddVehicleWheelOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java new file mode 100644 index 00000000..dc2b1a4c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java @@ -0,0 +1,62 @@ +package com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.objects.VehicleWheel; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveVehicleWheelOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.RemoveVehicleWheelOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to remove a vehicle wheel from a control. + * + * @author JavaSaBr + */ +public class RemoveVehicleWheelAction extends AbstractNodeAction { + + public RemoveVehicleWheelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected void process() { + + final TreeNode node = getNode(); + final Object element = node.getElement(); + final TreeNode nodeParent = notNull(node.getParent()); + final VehicleControl vehicleControl = (VehicleControl) nodeParent.getElement(); + final VehicleWheel vehicleWheel = (VehicleWheel) element; + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveVehicleWheelOperation(vehicleControl, vehicleWheel)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java new file mode 100644 index 00000000..8fb8e984 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java @@ -0,0 +1,64 @@ +package com.ss.builder.fx.control.tree.action.impl.geometry; + +import static com.ss.builder.util.EditorUtils.getDefaultLayer; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create the {@link Geometry}. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateGeometryAction extends AbstractNodeAction { + + public AbstractCreateGeometryAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + final SceneLayer defaultLayer = EditorUtils.getDefaultLayer(consumer); + + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Geometry geometry = createGeometry(); + geometry.setMaterial(new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md")); + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, geometry); + } + + consumer.execute(new AddChildOperation(geometry, parent)); + } + + /** + * Create geometry geometry. + * + * @return the geometry + */ + @FxThread + protected abstract @NotNull Geometry createGeometry(); +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateBoxAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateBoxAction.java new file mode 100644 index 00000000..9a2244d8 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateBoxAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.control.tree.action.impl.geometry; + +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create a {@link Geometry} with a {@link Box} mesh. + * + * @author JavaSaBr + */ +public class CreateBoxAction extends AbstractCreateGeometryAction { + + public CreateBoxAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.CUBE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_BOX; + } + + @Override + @FxThread + protected @NotNull Geometry createGeometry() { + return new Geometry("Box", new Box(1, 1, 1)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateQuadAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateQuadAction.java new file mode 100644 index 00000000..1baf6217 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateQuadAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.control.tree.action.impl.geometry; + +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create a {@link Geometry} with a {@link Quad} mesh. + * + * @author JavaSaBr + */ +public class CreateQuadAction extends AbstractCreateGeometryAction { + + public CreateQuadAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PLANE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_QUAD; + } + + @Override + @FxThread + protected @NotNull Geometry createGeometry() { + return new Geometry("Quad", new Quad(2, 2)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateSphereAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateSphereAction.java new file mode 100644 index 00000000..6a6a5030 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/CreateSphereAction.java @@ -0,0 +1,47 @@ +package com.ss.builder.fx.control.tree.action.impl.geometry; + +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create a {@link Geometry} with a {@link Sphere} mesh. + * + * @author JavaSaBr + */ +public class CreateSphereAction extends AbstractCreateGeometryAction { + + public CreateSphereAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.SPHERE_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_SPHERE; + } + + @Override + @FxThread + protected @NotNull Geometry createGeometry() { + return new Geometry("Sphere", new Sphere(30, 30, 1)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/GenerateLoDAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/GenerateLoDAction.java new file mode 100644 index 00000000..78fb1480 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/geometry/GenerateLoDAction.java @@ -0,0 +1,53 @@ +package com.ss.builder.fx.control.tree.action.impl.geometry; + +import com.jme3.scene.Geometry; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.spatial.GeometryTreeNode; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.dialog.geometry.lod.GenerateLodLevelsDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.ClassUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to generate levels of details for the geometry. + * + * @author JavaSaBr + */ +public class GenerateLoDAction extends AbstractNodeAction { + + public GenerateLoDAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_LOD_GENERATOR; + } + + @Override + @FxThread + protected void process() { + final GeometryTreeNode modelNode = ClassUtils.unsafeCast(getNode()); + final Geometry geometry = modelNode.getElement(); + final GenerateLodLevelsDialog dialog = new GenerateLodLevelsDialog(getNodeTree(), geometry); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/AbstractCreateLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/AbstractCreateLightAction.java new file mode 100644 index 00000000..4c1d9abc --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/AbstractCreateLightAction.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.control.tree.action.impl.light; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddLightOperation; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddLightOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create a {@link Light}. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateLightAction extends AbstractNodeAction { + + public AbstractCreateLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + + final Light light = createLight(); + if (light.getName() == null) { + light.setName(""); + } + + final TreeNode treeNode = getNode(); + final Node element = (Node) treeNode.getElement(); + + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new AddLightOperation(light, element)); + } + + /** + * Create light light. + * + * @return the light + */ + @FxThread + protected abstract @NotNull Light createLight(); +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateAmbientLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateAmbientLightAction.java new file mode 100644 index 00000000..45713453 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateAmbientLightAction.java @@ -0,0 +1,49 @@ +package com.ss.builder.fx.control.tree.action.impl.light; + +import com.jme3.light.AmbientLight; +import com.jme3.light.Light; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create an {@link AmbientLight}. + * + * @author JavaSaBr + */ +public class CreateAmbientLightAction extends AbstractCreateLightAction { + + public CreateAmbientLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.AMBIENT_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_AMBIENT_LIGHT; + } + + @Override + @FxThread + protected @NotNull Light createLight() { + final AmbientLight ambientLight = new AmbientLight(); + ambientLight.setName(Messages.MODEL_NODE_TREE_ACTION_AMBIENT_LIGHT); + return ambientLight; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateDirectionLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateDirectionLightAction.java new file mode 100644 index 00000000..17016e26 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateDirectionLightAction.java @@ -0,0 +1,49 @@ +package com.ss.builder.fx.control.tree.action.impl.light; + +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create a {@link DirectionalLight}. + * + * @author JavaSaBr + */ +public class CreateDirectionLightAction extends AbstractCreateLightAction { + + public CreateDirectionLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.SUN_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_DIRECTION_LIGHT; + } + + @Override + @FxThread + protected @NotNull Light createLight() { + final DirectionalLight directionalLight = new DirectionalLight(); + directionalLight.setName(Messages.MODEL_NODE_TREE_ACTION_DIRECTION_LIGHT); + return directionalLight; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreatePointLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreatePointLightAction.java new file mode 100644 index 00000000..f9d08386 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreatePointLightAction.java @@ -0,0 +1,48 @@ +package com.ss.builder.fx.control.tree.action.impl.light; + +import com.jme3.light.Light; +import com.jme3.light.PointLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link PointLight}. + * + * @author JavaSaBr + */ +public class CreatePointLightAction extends AbstractCreateLightAction { + + public CreatePointLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.POINT_LIGHT_16; + } + + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_POINT_LIGHT; + } + + @Override + @FxThread + protected @NotNull Light createLight() { + final PointLight pointLight = new PointLight(); + pointLight.setName(Messages.MODEL_NODE_TREE_ACTION_POINT_LIGHT); + return pointLight; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateSpotLightAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateSpotLightAction.java new file mode 100644 index 00000000..b7c55940 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/light/CreateSpotLightAction.java @@ -0,0 +1,49 @@ +package com.ss.builder.fx.control.tree.action.impl.light; + +import com.jme3.light.Light; +import com.jme3.light.SpotLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; + +/** + * The action to create a {@link SpotLight}. + * + * @author JavaSaBr + */ +public class CreateSpotLightAction extends AbstractCreateLightAction { + + public CreateSpotLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.LAMP_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_SPOT_LIGHT; + } + + @Override + @FxThread + protected @NotNull Light createLight() { + final SpotLight spotLight = new SpotLight(); + spotLight.setName(Messages.MODEL_NODE_TREE_ACTION_SPOT_LIGHT); + return spotLight; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/multi/RemoveElementsAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/multi/RemoveElementsAction.java new file mode 100644 index 00000000..b6f35028 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/multi/RemoveElementsAction.java @@ -0,0 +1,98 @@ +package com.ss.builder.fx.control.tree.action.impl.multi; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.RemoveElementsOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.RemoveElementsOperation; +import com.ss.builder.model.undo.impl.RemoveElementsOperation.Element; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.builder.fx.control.tree.node.impl.light.LightTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.SpatialTreeNode; +import com.ss.rlib.common.function.TripleConsumer; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayCollectors; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The action to remove some elements from a scene/model. + * + * @author JavaSaBr + */ +public class RemoveElementsAction extends AbstractNodeAction { + + private static final Array> AVAILABLE_TYPES = ArrayFactory.newArray(Class.class); + + static { + AVAILABLE_TYPES.add(SpatialTreeNode.class); + AVAILABLE_TYPES.add(ControlTreeNode.class); + AVAILABLE_TYPES.add(LightTreeNode.class); + AVAILABLE_TYPES.add(AnimationTreeNode.class); + } + + public static final NodeTree.MultiItemActionFiller ACTION_FILLER = (nodeTree, menuItems, treeNodes) -> { + + var unexpectedItem = treeNodes.findAny(treeNode -> + AVAILABLE_TYPES.findAny(treeNode, Class::isInstance) == null || !treeNode.canRemove()); + + if (unexpectedItem == null) { + menuItems.add(new RemoveElementsAction(nodeTree, treeNodes)); + } + }; + + public RemoveElementsAction(@NotNull NodeTree nodeTree, @NotNull Array> nodes) { + super(nodeTree, nodes); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + public void process() { + super.process(); + + var nodes = getNodes(); + var toRemove = nodes.stream() + .filter(treeNode -> treeNode.getParent() != null) + .map(this::convert) + .collect(ArrayCollectors.toArray(RemoveElementsOperation.Element.class)); + + getNodeTree().requireChangeConsumer() + .execute(new RemoveElementsOperation(toRemove)); + } + + @FxThread + private @NotNull RemoveElementsOperation.Element convert(@NotNull TreeNode treeNode) { + var value = treeNode.getElement(); + var parentNode = notNull(treeNode.getParent()); + var parent = parentNode.getElement(); + return new RemoveElementsOperation.Element(value, parent); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java new file mode 100644 index 00000000..735e153c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java @@ -0,0 +1,99 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter; + +import static com.ss.builder.util.EditorUtils.getDefaultLayer; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.AssetManager; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.EditorUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action for creating new {@link ParticleEmitter}. + * + * @author JavaSaBr + */ +public class CreateParticleEmitterAction extends AbstractNodeAction { + + public CreateParticleEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.EMITTER_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_DEFAULT_PARTICLE_EMITTER; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + final SceneLayer defaultLayer = EditorUtils.getDefaultLayer(changeConsumer); + + final AssetManager assetManager = EditorUtils.getAssetManager(); + final Material material = new Material(assetManager,"Common/MatDefs/Misc/Particle.j3md"); + material.setTexture("Texture", assetManager.loadTexture( "Effects/Explosion/flame.png")); + + final ParticleEmitter emitter = createParticleEmitter(); + emitter.setMaterial(material); + emitter.setImagesX(2); + emitter.setImagesY(2); // 2x2 texture animation + emitter.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red + emitter.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow + emitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0)); + emitter.setStartSize(1.5f); + emitter.setEndSize(0.1f); + emitter.setGravity(0, 0, 0); + emitter.setLowLife(1f); + emitter.setHighLife(3f); + emitter.getParticleInfluencer().setVelocityVariation(0.3f); + emitter.setEnabled(true); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, emitter); + } + + final TreeNode treeNode = getNode(); + final Node parent = (Node) treeNode.getElement(); + + changeConsumer.execute(new AddChildOperation(emitter, parent)); + } + + @FxThread + protected @NotNull ParticleEmitter createParticleEmitter() { + return new ParticleEmitter("Default Emitter", ParticleMesh.Type.Triangle, 30); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java new file mode 100644 index 00000000..c96b4f24 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java @@ -0,0 +1,78 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter; + +import static com.ss.builder.util.NodeUtils.visitSpatial; +import com.jme3.effect.ParticleEmitter; +import com.jme3.scene.Node; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to reset a {@link ParticleEmitter}. + * + * @author JavaSaBr + */ +public class ResetParticleEmittersAction extends AbstractNodeAction { + + /** + * @see AdditionalAction + */ + public static final String EP_ADDITIONAL_ACTIONS = "ResetParticleEmittersAction#additionalActions"; + + private static final ExtensionPoint> ADDITIONAL_ACTIONS = + ExtensionPointManager.register(EP_ADDITIONAL_ACTIONS); + + public ResetParticleEmittersAction(@NotNull NodeTree nodeTree, @NotNull TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REPLAY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_RESET_PARTICLE_EMITTERS; + } + + @Override + @FxThread + protected void process() { + super.process(); + + var treeNode = getNode(); + var node = (Node) treeNode.getElement(); + + ExecutorManager.getInstance() + .addJmeTask(() -> NodeUtils.visitSpatial(node, ParticleEmitter.class, ParticleEmitter::killAllParticles)); + + ADDITIONAL_ACTIONS.forEach(node, (factory, toCheck) -> { + + var executorManager = ExecutorManager.getInstance(); + var action = factory.makeAction(toCheck); + + if (action != null) { + executorManager.addJmeTask(action); + } + }); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java new file mode 100644 index 00000000..299c1cb6 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java @@ -0,0 +1,61 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.emitter.ChangeParticleInfluencerOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.emitter.ChangeParticleInfluencerOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a {@link ParticleInfluencer} for a {@link ParticleEmitter}. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateParticleInfluencerAction extends AbstractNodeAction { + + public AbstractCreateParticleInfluencerAction(@NotNull final NodeTree nodeTree, + @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.INFLUENCER_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + + final TreeNode treeNode = getNode(); + final ParticleEmitter emitter = (ParticleEmitter) treeNode.getElement(); + final ParticleInfluencer influencer = createInfluencer(); + + changeConsumer.execute(new ChangeParticleInfluencerOperation(influencer, emitter)); + } + + /** + * Create influencer particle influencer. + * + * @return the particle influencer + */ + @FxThread + protected abstract @NotNull ParticleInfluencer createInfluencer(); +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java new file mode 100644 index 00000000..04691b42 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer; + +import com.jme3.effect.influencers.DefaultParticleInfluencer; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create an {@link DefaultParticleInfluencer}. + * + * @author JavaSaBr + */ +public class CreateDefaultParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { + + public CreateDefaultParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull ParticleInfluencer createInfluencer() { + return new DefaultParticleInfluencer(); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_DEFAULT; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java new file mode 100644 index 00000000..8b8c7f9c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer; + +import com.jme3.effect.influencers.EmptyParticleInfluencer; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create an {@link EmptyParticleInfluencer}. + * + * @author JavaSaBr + */ +public class CreateEmptyParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { + + public CreateEmptyParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull ParticleInfluencer createInfluencer() { + return new EmptyParticleInfluencer(); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_EMPTY; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java new file mode 100644 index 00000000..f27da222 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java @@ -0,0 +1,36 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer; + +import com.jme3.effect.influencers.EmptyParticleInfluencer; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.jme3.effect.influencers.RadialParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The action to create an {@link EmptyParticleInfluencer}. + * + * @author JavaSaBr + */ +public class CreateRadialParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { + + public CreateRadialParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull ParticleInfluencer createInfluencer() { + return new RadialParticleInfluencer(); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_RADIAL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java new file mode 100644 index 00000000..3d1ec839 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java @@ -0,0 +1,116 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.shapes.EmitterShape; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.emitter.ChangeEmitterShapeOperation; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.emitter.ChangeEmitterShapeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +/** + * The action to switch an {@link EmitterShape} of the {@link ParticleEmitter}. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateShapeEmitterAction extends AbstractNodeAction { + + public AbstractCreateShapeEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.GEOMETRY_16; + } + + @FxThread + @Override + protected void process() { + super.process(); + + final Point dialogSize = getDialogSize(); + + final GenericFactoryDialog dialog = new GenericFactoryDialog(getPropertyDefinitions(), this::handleResult); + dialog.setTitle(getDialogTitle()); + + if (dialogSize != null) { + dialog.updateSize(dialogSize); + } + + dialog.show(); + } + + /** + * Gets another dialog size. + * + * @return the dialog size or null. + */ + @FxThread + protected @Nullable Point getDialogSize() { + return null; + } + + /** + * Gets a dialog title. + * + * @return the dialog title. + */ + @FxThread + protected abstract @NotNull String getDialogTitle(); + + /** + * Handle the result from the dialog. + * + * @param vars the table with variables. + */ + @FxThread + private void handleResult(@NotNull final VarTable vars) { + + final TreeNode treeNode = getNode(); + final ParticleEmitter element = (ParticleEmitter) treeNode.getElement(); + final EmitterShape emitterShape = createEmitterShape(vars); + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new ChangeEmitterShapeOperation(emitterShape, element)); + } + + /** + * Gets a list of property definitions to create a shape. + * + * @return the list of definitions. + */ + @FxThread + protected abstract @NotNull Array getPropertyDefinitions(); + + /** + * Create emitter shape. + * + * @param vars the table with variables. + * @return the emitter shape. + */ + @FxThread + protected abstract @NotNull EmitterShape createEmitterShape(@NotNull final VarTable vars); +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java similarity index 86% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java index 10579d71..35e097a8 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateBoxShapeEmitterAction.java @@ -1,16 +1,16 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.shapes.EmitterBoxShape; import com.jme3.effect.shapes.EmitterShape; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java similarity index 76% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java index 493f8292..272de091 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshConvexHullShapeEmitterAction.java @@ -1,13 +1,15 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.shapes.EmitterMeshConvexHullShape; import com.jme3.effect.shapes.EmitterMeshVertexShape; import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import org.jetbrains.annotations.NotNull; import java.util.List; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java new file mode 100644 index 00000000..47690b97 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java @@ -0,0 +1,39 @@ +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.shapes.EmitterMeshFaceShape; +import com.jme3.effect.shapes.EmitterMeshVertexShape; +import com.jme3.scene.Mesh; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * The action to create a {@link EmitterMeshFaceShape} to the {@link ParticleEmitter}. + * + * @author JavaSaBr + */ +public class CreateMeshFaceShapeEmitterAction extends CreateMeshVertexShapeEmitterAction { + + public CreateMeshFaceShapeEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @NotNull EmitterMeshVertexShape createEmitterShape(@NotNull final List meshes) { + return new EmitterMeshFaceShape(meshes); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_MESH_FACE_SHAPE; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java similarity index 81% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java index 90db14d5..a2e83901 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateMeshVertexShapeEmitterAction.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; import static com.ss.editor.extension.property.EditablePropertyType.GEOMETRY_FROM_ASSET_FOLDER; import static java.util.Collections.singletonList; @@ -7,12 +7,16 @@ import com.jme3.effect.shapes.EmitterShape; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java similarity index 79% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java index e647b481..a1689116 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreatePointShapeEmitterAction.java @@ -1,16 +1,20 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.shapes.EmitterPointShape; import com.jme3.effect.shapes.EmitterShape; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java similarity index 81% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java index aba170d1..a165cd37 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/particle/emitter/shape/CreateSphereShapeEmitterAction.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; +package com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; @@ -6,12 +6,16 @@ import com.jme3.effect.shapes.EmitterShape; import com.jme3.effect.shapes.EmitterSphereShape; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java new file mode 100644 index 00000000..527f8091 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java @@ -0,0 +1,101 @@ +package com.ss.builder.fx.control.tree.action.impl.physics.shape; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.ChangeCollisionShapeOperation; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.dialog.GenericFactoryDialog; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.ChangeCollisionShapeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a new shape. + * + * @author JavaSaBr + */ +public abstract class AbstractCreateShapeAction extends AbstractNodeAction { + + AbstractCreateShapeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.GEOMETRY_16; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final Array definitions = getPropertyDefinitions(); + if (definitions.isEmpty()) return; + + final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, this::handleResult); + dialog.setTitle(getDialogTitle()); + dialog.show(); + } + + /** + * Gets a dialog title. + * + * @return the dialog title. + */ + @FxThread + protected abstract @NotNull String getDialogTitle(); + + /** + * Handle the result from the dialog. + * + * @param vars the table with variables. + */ + @FxThread + private void handleResult(@NotNull final VarTable vars) { + + final TreeNode treeNode = getNode(); + final PhysicsCollisionObject element = (PhysicsCollisionObject) treeNode.getElement(); + final CollisionShape shape = createShape(vars); + final CollisionShape currentShape = element.getCollisionShape(); + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new ChangeCollisionShapeOperation(shape, currentShape, element)); + } + + /** + * Gets a list of property definitions to create a shape. + * + * @return the list of definitions. + */ + @FxThread + protected abstract @NotNull Array getPropertyDefinitions(); + + /** + * Create a collision shape. + * + * @param vars the table with variables. + * @return the collision shape + */ + @FxThread + protected abstract @NotNull CollisionShape createShape(@NotNull final VarTable vars); +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java similarity index 79% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java index 947b99af..8d9e1e0f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateBoxCollisionShapeAction.java @@ -1,14 +1,17 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; import com.jme3.bullet.collision.shapes.BoxCollisionShape; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java similarity index 80% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java index 671f2d1d..1fc39c54 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCapsuleCollisionShapeAction.java @@ -1,14 +1,18 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; import com.jme3.bullet.collision.shapes.CollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java similarity index 82% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java index 34a60478..24d73322 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateConeCollisionShapeAction.java @@ -1,15 +1,19 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.ss.editor.extension.property.EditablePropertyType.ENUM; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.collision.shapes.ConeCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java index 034c0518..8e2c56b5 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateCylinderCollisionShapeAction.java @@ -1,17 +1,21 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.ss.editor.extension.property.EditablePropertyType.ENUM; import static com.ss.editor.extension.property.EditablePropertyType.VECTOR_3F; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.collision.shapes.CylinderCollisionShape; import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.physics.shape.CreateConeCollisionShapeAction.Axis; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.physics.shape.CreateConeCollisionShapeAction.Axis; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java index 316607d8..9baab668 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/CreateSphereCollisionShapeAction.java @@ -1,14 +1,18 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.collision.shapes.SphereCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java similarity index 82% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java rename to src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java index 9f19a382..2a76b025 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; +package com.ss.builder.fx.control.tree.action.impl.physics.shape; import static com.jme3.bullet.util.CollisionShapeFactory.createDynamicMeshShape; import static com.jme3.bullet.util.CollisionShapeFactory.createMeshShape; @@ -14,14 +14,20 @@ import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.ChangeCollisionShapeOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.ChangeCollisionShapeOperation; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.undo.impl.ChangeCollisionShapeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/CreateSceneLayerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/CreateSceneLayerAction.java new file mode 100644 index 00000000..008cd522 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/CreateSceneLayerAction.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.tree.action.impl.scene; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.scene.AddSceneLayerOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.fx.control.tree.node.impl.layer.LayersRootTreeNode; +import com.ss.builder.model.undo.impl.scene.AddSceneLayerOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create a scene layer. + * + * @author JavaSaBr + */ +public class CreateSceneLayerAction extends AbstractNodeAction { + + public CreateSceneLayerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.LAYERS_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_CREATE_LAYER; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final SceneLayer layer = new SceneLayer("New Layer", false); + final LayersRootTreeNode modelNode = (LayersRootTreeNode) getNode(); + final LayersRoot element = modelNode.getElement(); + final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); + final SceneNode sceneNode = changeConsumer.getCurrentModel(); + + changeConsumer.execute(new AddSceneLayerOperation(element, layer, sceneNode)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/RemoveSceneLayerAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/RemoveSceneLayerAction.java new file mode 100644 index 00000000..94a62b16 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/scene/RemoveSceneLayerAction.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.tree.action.impl.scene; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.scene.RemoveSceneLayerOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.fx.control.tree.node.impl.layer.SceneLayerTreeNode; +import com.ss.builder.model.undo.impl.scene.RemoveSceneLayerOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to remove a scene layer. + * + * @author JavaSaBr + */ +public class RemoveSceneLayerAction extends AbstractNodeAction { + + public RemoveSceneLayerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected void process() { + super.process(); + + final NodeTree nodeTree = getNodeTree(); + final SceneChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + final SceneNode sceneNode = changeConsumer.getCurrentModel(); + + final SceneLayerTreeNode modelNode = (SceneLayerTreeNode) getNode(); + final SceneLayer layer = modelNode.getElement(); + + changeConsumer.execute(new RemoveSceneLayerOperation(new LayersRoot(changeConsumer), layer, sceneNode)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/action/impl/terrain/CreateTerrainAction.java b/src/main/java/com/ss/builder/fx/control/tree/action/impl/terrain/CreateTerrainAction.java new file mode 100644 index 00000000..9e7d0428 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/action/impl/terrain/CreateTerrainAction.java @@ -0,0 +1,49 @@ +package com.ss.builder.fx.control.tree.action.impl.terrain; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.dialog.terrain.CreateTerrainDialog; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to create terrain. + * + * @author JavaSaBr + */ +public class CreateTerrainAction extends AbstractNodeAction { + + public CreateTerrainAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.TERRAIN_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ADD_TERRAIN; + } + + @Override + @FxThread + protected void process() { + super.process(); + final CreateTerrainDialog dialog = new CreateTerrainDialog(getNode(), getNodeTree()); + dialog.show(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/HideableNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/HideableNode.java new file mode 100644 index 00000000..a0a32742 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/HideableNode.java @@ -0,0 +1,37 @@ +package com.ss.builder.fx.control.tree.node; + +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; + +import org.jetbrains.annotations.NotNull; + +/** + * The interface-marker that an object can be hide. + * + * @param the type parameter + * @author JavaSaBr + */ +public interface HideableNode { + + /** + * Is hided boolean. + * + * @return true if this object is hided. + */ + boolean isHided(); + + /** + * Show the object. + * + * @param nodeTree the node tree + */ + void show(@NotNull NodeTree nodeTree); + + /** + * Hide the object. + * + * @param nodeTree the node tree + */ + void hide(@NotNull NodeTree nodeTree); +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/TreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/TreeNode.java new file mode 100644 index 00000000..2c64dea2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/TreeNode.java @@ -0,0 +1,414 @@ +package com.ss.builder.fx.control.tree.node; + +import static com.ss.builder.fx.control.tree.NodeTreeCell.DATA_FORMAT; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.UObject; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.action.impl.CopyNodeAction; +import com.ss.builder.fx.control.tree.action.impl.PasteNodeAction; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactoryRegistry; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.UObject; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.tree.action.impl.CopyNodeAction; +import com.ss.builder.fx.control.tree.action.impl.PasteNodeAction; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.AbstractNodeAction; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactoryRegistry; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TreeItem; +import javafx.scene.image.Image; +import javafx.scene.input.Clipboard; +import javafx.scene.input.Dragboard; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.Objects; + +/** + * The base implementation of a tree node. + * + * @param the type of presented element + * @author JavaSaBr + */ +public abstract class TreeNode implements UObject { + + protected static final TreeNodeFactoryRegistry FACTORY_REGISTRY = TreeNodeFactoryRegistry.getInstance(); + + /** + * The action's comparator. + */ + protected static final Comparator ACTION_COMPARATOR = (first, second) -> { + if (first instanceof Menu) { + return -1; + } else if (second instanceof Menu) { + return 1; + } else if (first instanceof AbstractNodeAction) { + return ((AbstractNodeAction) first).compareTo(second); + } else { + return 0; + } + }; + + /** + * The uniq id of this node. + */ + private final long objectId; + + /** + * The wrapped element. + */ + @NotNull + private final T element; + + /** + * The parent node. + */ + @Nullable + private TreeNode parent; + + public TreeNode(@NotNull T element, long objectId) { + this.element = element; + this.objectId = objectId; + } + + /** + * Get the wrapped element. + * + * @return the wrapped element. + */ + @FromAnyThread + public @NotNull T getElement() { + return element; + } + + /** + * Get the name of this node. + * + * @return the name of this node. + */ + @FromAnyThread + public @NotNull String getName() { + return "unknown name"; + } + + /** + * Set the name of this node. + * + * @param name the name of this node. + */ + @FxThread + public void setName(@NotNull String name) { + } + + /** + * Is need to save name. + * + * @return true if need to save name. + */ + @FromAnyThread + public boolean isNeedToSaveName() { + return false; + } + + /** + * Has children boolean. + * + * @param nodeTree the node tree + * @return true of this node has any children. + */ + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return false; + } + + /** + * Get the children. + * + * @param nodeTree the node tree + * @return the array of children of this node. + */ + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + return Array.empty(); + } + + /** + * Get the parent. + * + * @return the parent of this node or null. + */ + @FxThread + public @Nullable TreeNode getParent() { + return parent; + } + + /** + * Set the parent node. + * + * @param parent the parent node. + */ + @FxThread + protected void setParent(@Nullable TreeNode parent) { + this.parent = parent; + } + + /** + * Get the icon of this node. + * + * @return the icon of this node or null. + */ + @FxThread + public @Nullable Image getIcon() { + return null; + } + + /** + * Fill the items actions for this node. + * + * @param nodeTree the node tree + * @param items the items + */ + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + if (canEditName()) { + items.add(new RenameNodeAction(nodeTree, this)); + } + + if (canCopy()) { + items.add(new CopyNodeAction(nodeTree, this)); + } + + var clipboard = Clipboard.getSystemClipboard(); + // added good method to fx lib + var content = clipboard.getContent(DATA_FORMAT); + if (!(content instanceof Long)) { + return; + } + + var objectId = (Long) content; + var treeItem = UiUtils.findItem(nodeTree.getTreeView(), objectId); + var treeNode = treeItem == null ? null : treeItem.getValue(); + + if (treeNode != null && canAccept(treeNode, true)) { + items.add(new PasteNodeAction(nodeTree, this, treeNode)); + } + } + + /** + * Handle the result context menu. + * + * @param nodeTree the node tree. + * @param items the result items. + */ + @FxThread + public void handleResultContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + items.sort(ACTION_COMPARATOR); + } + + /** + * Remove the child from this node. + * + * @param child the child + */ + @FxThread + public void remove(@NotNull TreeNode child) { + } + + /** + * Add the new child to this node. + * + * @param child the child + */ + @FxThread + public void add(@NotNull TreeNode child) { + } + + /** + * Handle changing the name of this node. + * + * @param nodeTree the node tree + * @param newName the new name + */ + @FxThread + public void changeName(@NotNull NodeTree nodeTree, @NotNull String newName) { + } + + /** + * Check of possibility to accept the tree node as a new child. + * + * @param treeNode the node. + * @param isCopy true if need to copy the node. + * @return true if this node can be accept. + */ + @FxThread + public boolean canAccept(@NotNull TreeNode treeNode, boolean isCopy) { + return false; + } + + /** + * Accept the object to this node. + * + * @param changeConsumer the change consumer. + * @param object the object. + * @param isCopy true if need to copy the object. + */ + @FxThread + public void accept(@NotNull ChangeConsumer changeConsumer, @NotNull Object object, boolean isCopy) { + } + + /** + * Can accept external boolean. + * + * @param dragboard the dragboard + * @return true if this node can accept external resource. + */ + @FxThread + public boolean canAcceptExternal(@NotNull Dragboard dragboard) { + return false; + } + + /** + * Accept external resources to this node. + * + * @param dragboard the dragboard + * @param consumer the consumer + */ + @FxThread + public void acceptExternal(@NotNull Dragboard dragboard, @NotNull ChangeConsumer consumer) { + } + + /** + * Can move boolean. + * + * @return true if this node supports moving. + */ + @FxThread + public boolean canMove() { + return false; + } + + /** + * Can copy boolean. + * + * @return true if this node supports copying. + */ + @FxThread + public boolean canCopy() { + return false; + } + + /** + * Can edit name boolean. + * + * @return true if this node supports name editing. + */ + @FxThread + public boolean canEditName() { + return false; + } + + /** + * Can remove boolean. + * + * @return true if you can remove this node. + */ + @FxThread + public boolean canRemove() { + return true; + } + + /** + * Copy model node. + * + * @return the new copy of this node. + */ + @FxThread + public @NotNull TreeNode copy() { + throw new UnsupportedOperationException(); + } + + @Override + @FromAnyThread + public long getObjectId() { + return objectId; + } + + @Override + public String toString() { + return getName(); + } + + @Override + public boolean equals(@Nullable Object other) { + + if (this == other) { + return true; + } else if (other == null) { + return false; + } + + if (other instanceof TreeNode) { + var treeNode = (TreeNode) other; + return element.equals(treeNode.element); + } + + return Objects.equals(element, other); + } + + @Override + public int hashCode() { + return element.hashCode(); + } + + /** + * Notify about that a model node was added to children of this node. + * + * @param treeNode the model node. + */ + @FxThread + public void notifyChildAdded(@NotNull TreeNode treeNode) { + } + + /** + * Notify about that a model node was removed from children of this node. + * + * @param treeNode the model node. + */ + @FxThread + public void notifyChildRemoved(@NotNull TreeNode treeNode) { + treeNode.setParent(null); + } + + /** + * Notify about that a model node will add to children of this node. + * + * @param treeNode the model node. + */ + @FxThread + public void notifyChildPreAdd(@NotNull TreeNode treeNode) { + treeNode.setParent(this); + } + + /** + * Notify about that a model node will remove from children of this node. + * + * @param treeNode the model node. + */ + @FxThread + public void notifyChildPreRemove(@NotNull TreeNode treeNode) { + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactory.java similarity index 82% rename from src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java rename to src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactory.java index 285b8560..20330aa1 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactory.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.control.tree.node.factory; +package com.ss.builder.fx.control.tree.node.factory; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.TreeNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactoryRegistry.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactoryRegistry.java new file mode 100644 index 00000000..267cb60a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/TreeNodeFactoryRegistry.java @@ -0,0 +1,93 @@ +package com.ss.builder.fx.control.tree.node.factory; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.factory.impl.*; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.impl.*; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * The registry of available tree node factories. + * + * @author JavaSaBr + */ +public class TreeNodeFactoryRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(TreeNodeFactoryRegistry.class); + + /** + * @see TreeNodeFactory + */ + public static final String EP_FACTORIES = "TreeNodeFactoryRegistry#factories"; + + private static final ExtensionPoint FACTORIES = + ExtensionPointManager.register(EP_FACTORIES); + + /** + * The node's id generator. + */ + private static final AtomicLong ID_GENERATOR = new AtomicLong(); + + private static final TreeNodeFactoryRegistry INSTANCE = new TreeNodeFactoryRegistry(); + + @FromAnyThread + public static @NotNull TreeNodeFactoryRegistry getInstance() { + return INSTANCE; + } + + private TreeNodeFactoryRegistry() { + + FACTORIES.register(new PrimitiveTreeNodeFactory()) + .register(new LegacyAnimationTreeNodeFactory()) + .register(new CollisionTreeNodeFactory()) + .register(new ControlTreeNodeFactory()) + .register(new DefaultParticlesTreeNodeFactory()) + .register(new DefaultTreeNodeFactory()) + .register(new LightTreeNodeFactory()) + .register(new MaterialSettingsTreeNodeFactory()) + .register(new AnimationTreeNodeFactory()); + + LOGGER.info("initialized."); + } + + /** + * Create a tree node for the element. + * + * @param the element's type. + * @param the tree node's type. + * @param element the element + * @return the created tree node or null. + */ + @FxThread + public > @Nullable V createFor(@Nullable T element) { + + if (element instanceof TreeNode) { + return unsafeCast(element); + } + + var factories = FACTORIES.getExtensions(); + var objectId = ID_GENERATOR.incrementAndGet(); + + V result = null; + + for (var factory : factories) { + result = factory.createFor(element, objectId); + if (result != null) { + break; + } + } + + return result; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/AnimationTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/AnimationTreeNodeFactory.java new file mode 100644 index 00000000..afc682fd --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/AnimationTreeNodeFactory.java @@ -0,0 +1,42 @@ +package com.ss.builder.fx.control.tree.node.factory.impl; + +import com.jme3.anim.AnimClip; +import com.jme3.anim.AnimComposer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.fx.control.tree.node.impl.control.anim.AnimationClipTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.anim.AnimationControlTreeNode; +import org.jetbrains.annotations.Nullable; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; + +/** + * The implementation of a tree node factory to make animation nodes. + * + * @author JavaSaBr + */ +public class AnimationTreeNodeFactory implements TreeNodeFactory { + + public static final int PRIORITY = 1; + + @Override + @FxThread + public > @Nullable V createFor(@Nullable T element, long objectId) { + + if (element instanceof AnimComposer) { + return unsafeCast(new AnimationControlTreeNode((AnimComposer) element, objectId)); + } else if (element instanceof AnimClip) { + return unsafeCast(new AnimationClipTreeNode((AnimClip) element, objectId)); + } + + return null; + } + + @Override + @FxThread + public int getPriority() { + return PRIORITY; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/CollisionTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/CollisionTreeNodeFactory.java similarity index 88% rename from src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/CollisionTreeNodeFactory.java rename to src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/CollisionTreeNodeFactory.java index 830c6db5..76a9176a 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/CollisionTreeNodeFactory.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/CollisionTreeNodeFactory.java @@ -1,12 +1,13 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; +package com.ss.builder.fx.control.tree.node.factory.impl; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.bullet.collision.shapes.*; import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.physics.shape.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.physics.shape.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; import org.jetbrains.annotations.Nullable; /** diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/ControlTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/ControlTreeNodeFactory.java new file mode 100644 index 00000000..c27b6b21 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/ControlTreeNodeFactory.java @@ -0,0 +1,54 @@ +package com.ss.builder.fx.control.tree.node.factory.impl; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.jme3.animation.SkeletonControl; +import com.jme3.bullet.control.*; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.scene.control.Control; +import com.jme3.scene.control.LightControl; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.LightControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.SkeletonControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.motion.MotionEventTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.physics.BetterCharacterControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.physics.RagdollControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.physics.RigidBodyControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.physics.vehicle.VehicleControlTreeNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of a tree node factory to make control nodes. + * + * @author JavaSaBr + */ +public class ControlTreeNodeFactory implements TreeNodeFactory { + + @Override + @FxThread + public > @Nullable V createFor(@Nullable final T element, final long objectId) { + + if (element instanceof MotionEvent) { + return unsafeCast(new MotionEventTreeNode((MotionEvent) element, objectId)); + } else if (element instanceof KinematicRagdollControl) { + return unsafeCast(new RagdollControlTreeNode((KinematicRagdollControl) element, objectId)); + } else if (element instanceof VehicleControl) { + return unsafeCast(new VehicleControlTreeNode((VehicleControl) element, objectId)); + } else if (element instanceof SkeletonControl) { + return unsafeCast(new SkeletonControlTreeNode((SkeletonControl) element, objectId)); + } else if (element instanceof BetterCharacterControl) { + return unsafeCast(new BetterCharacterControlTreeNode((BetterCharacterControl) element, objectId)); + } else if (element instanceof RigidBodyControl) { + return unsafeCast(new RigidBodyControlTreeNode((RigidBodyControl) element, objectId)); + } else if (element instanceof LightControl) { + return unsafeCast(new LightControlTreeNode((LightControl) element, objectId)); + } else if (element instanceof Control) { + return unsafeCast(new ControlTreeNode<>((Control) element, objectId)); + } + + return null; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java similarity index 76% rename from src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java rename to src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java index 2a1658bc..d3ff7529 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; +package com.ss.builder.fx.control.tree.node.factory.impl; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.effect.ParticleEmitter; @@ -7,15 +7,16 @@ import com.jme3.effect.influencers.ParticleInfluencer; import com.jme3.effect.influencers.RadialParticleInfluencer; import com.jme3.effect.shapes.*; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.ParticleEmitterTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer.DefaultParticleInfluencerTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer.EmptyParticleInfluencerTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer.ParticleInfluencerTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer.RadialParticleInfluencerTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.ParticleEmitterTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer.DefaultParticleInfluencerTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer.EmptyParticleInfluencerTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer.ParticleInfluencerTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer.RadialParticleInfluencerTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; import org.jetbrains.annotations.Nullable; /** diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultTreeNodeFactory.java similarity index 75% rename from src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java rename to src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultTreeNodeFactory.java index 1718bb8e..cec94c7b 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/DefaultTreeNodeFactory.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; +package com.ss.builder.fx.control.tree.node.factory.impl; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.audio.AudioNode; @@ -10,21 +10,25 @@ import com.jme3.scene.Node; import com.jme3.terrain.geomipmap.TerrainGrid; import com.jme3.terrain.geomipmap.TerrainQuad; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.scene.SceneAppStatesNode; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneLayer; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.model.scene.SceneAppStatesNode; -import com.ss.editor.model.scene.SceneFiltersNode; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; -import com.ss.editor.ui.control.tree.node.impl.layer.LayersRootTreeNode; -import com.ss.editor.ui.control.tree.node.impl.layer.SceneLayerTreeNode; -import com.ss.editor.ui.control.tree.node.impl.scene.*; -import com.ss.editor.ui.control.tree.node.impl.spatial.*; -import com.ss.editor.ui.control.tree.node.impl.spatial.terrain.TerrainGridTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.terrain.TerrainQuadTreeNode; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.scene.SceneAppStatesNode; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.fx.control.tree.node.impl.layer.LayersRootTreeNode; +import com.ss.builder.fx.control.tree.node.impl.layer.SceneLayerTreeNode; +import com.ss.builder.fx.control.tree.node.impl.scene.*; +import com.ss.builder.fx.control.tree.node.impl.spatial.*; +import com.ss.builder.fx.control.tree.node.impl.spatial.terrain.TerrainGridTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.terrain.TerrainQuadTreeNode; import org.jetbrains.annotations.Nullable; /** diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LegacyAnimationTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LegacyAnimationTreeNodeFactory.java new file mode 100644 index 00000000..45410439 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LegacyAnimationTreeNodeFactory.java @@ -0,0 +1,48 @@ +package com.ss.builder.fx.control.tree.node.factory.impl; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.jme3.animation.*; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of a tree node factory to make animation nodes. + * + * @author JavaSaBr + */ +@Deprecated +public class LegacyAnimationTreeNodeFactory implements TreeNodeFactory { + + public static final int PRIORITY = 1; + + @Override + @FxThread + public > @Nullable V createFor(@Nullable T element, long objectId) { + + if (element instanceof Animation) { + return unsafeCast(new AnimationTreeNode((Animation) element, objectId)); + } else if (element instanceof BoneTrack) { + return unsafeCast(new AnimationBoneTrackTreeNode((BoneTrack) element, objectId)); + } else if (element instanceof EffectTrack) { + return unsafeCast(new AnimationEffectTrackTreeNode((EffectTrack) element, objectId)); + } else if (element instanceof AudioTrack) { + return unsafeCast(new AnimationAudioTrackTreeNode((AudioTrack) element, objectId)); + } else if (element instanceof SpatialTrack) { + return unsafeCast(new AnimationSpatialTrackTreeNode((SpatialTrack) element, objectId)); + } else if (element instanceof AnimControl) { + return unsafeCast(new AnimationControlTreeNode((AnimControl) element, objectId)); + } + + return null; + } + + @Override + @FxThread + public int getPriority() { + return PRIORITY; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/LightTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LightTreeNodeFactory.java similarity index 78% rename from src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/LightTreeNodeFactory.java rename to src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LightTreeNodeFactory.java index d5c846cf..35dc45bf 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/LightTreeNodeFactory.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/LightTreeNodeFactory.java @@ -1,11 +1,12 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; +package com.ss.builder.fx.control.tree.node.factory.impl; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.light.*; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.light.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.light.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; import org.jetbrains.annotations.Nullable; /** diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java new file mode 100644 index 00000000..51750610 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.factory.impl; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.*; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import com.ss.builder.fx.control.tree.node.impl.material.settings.*; +import org.jetbrains.annotations.Nullable; + +/** + * The factory to create material settings nodes. + * + * @author JavaSaBr + */ +public class MaterialSettingsTreeNodeFactory implements TreeNodeFactory { + + @Override + @FxThread + public > @Nullable V createFor(@Nullable final T element, final long objectId) { + + if (element instanceof RootMaterialSettings) { + return unsafeCast(new RootMaterialSettingsTreeNode((RootMaterialSettings) element, objectId)); + } else if (element instanceof TexturesSettings) { + return unsafeCast(new TexturesSettingsTreeNode((TexturesSettings) element, objectId)); + } else if (element instanceof ColorsSettings) { + return unsafeCast(new ColorsSettingsTreeNode((ColorsSettings) element, objectId)); + } else if (element instanceof RenderSettings) { + return unsafeCast(new RenderSettingsTreeNode((RenderSettings) element, objectId)); + } else if (element instanceof OtherSettings) { + return unsafeCast(new OtherSettingsTreeNode((OtherSettings) element, objectId)); + } + + return null; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java new file mode 100644 index 00000000..7001c847 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java @@ -0,0 +1,54 @@ +package com.ss.builder.fx.control.tree.node.factory.impl; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.cinematic.MotionPath; +import com.jme3.math.Vector3f; +import com.jme3.scene.VertexBuffer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.tree.node.impl.BufferTreeNode; +import com.ss.builder.fx.control.tree.node.impl.PositionTreeNode; +import com.ss.builder.fx.control.tree.node.impl.VertexBufferTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.motion.MotionPathTreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.physics.vehicle.VehicleWheelTreeNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.factory.TreeNodeFactory; +import org.jetbrains.annotations.Nullable; + +import java.nio.Buffer; + +/** + * The implementation of a tree node factory to make primitive nodes. + * + * @author JavaSaBr + */ +public class PrimitiveTreeNodeFactory implements TreeNodeFactory { + + public static final int PRIORITY = 1; + + @Override + @FxThread + public > @Nullable V createFor(@Nullable final T element, final long objectId) { + + if (element instanceof Vector3f) { + return unsafeCast(new PositionTreeNode((Vector3f) element, objectId)); + } else if (element instanceof VertexBuffer) { + return unsafeCast(new VertexBufferTreeNode((VertexBuffer) element, objectId)); + } else if (element instanceof Buffer) { + return unsafeCast(new BufferTreeNode((Buffer) element, objectId)); + } else if (element instanceof VehicleWheel) { + return unsafeCast(new VehicleWheelTreeNode((VehicleWheel) element, objectId)); + } else if (element instanceof MotionPath) { + return unsafeCast(new MotionPathTreeNode((MotionPath) element, objectId)); + } + + return null; + } + + @Override + @FxThread + public int getPriority() { + return PRIORITY; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/BufferTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/BufferTreeNode.java new file mode 100644 index 00000000..7969a4a2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/BufferTreeNode.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.control.tree.node.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.Buffer; + +/** + * The implementation of the {@link TreeNode} to represent the {@link Buffer} in the editor. + * + * @author JavaSaBr + */ +public class BufferTreeNode extends TreeNode { + + public BufferTreeNode(@NotNull Buffer element, long objectId) { + super(element, objectId); + } + + @Override + public @Nullable Image getIcon() { + return Icons.DATA_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return getElement().getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/PositionTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/PositionTreeNode.java new file mode 100644 index 00000000..eebfcfe5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/PositionTreeNode.java @@ -0,0 +1,55 @@ +package com.ss.builder.fx.control.tree.node.impl; + +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show vectors in the tree. + * + * @author JavaSaBr + */ +public class PositionTreeNode extends TreeNode { + + /** + * The name. + */ + @Nullable + private String name; + + public PositionTreeNode(@NotNull Vector3f element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.WAY_POINT_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return name == null ? "Point 3D" : name; + } + + @Override + @FxThread + public boolean isNeedToSaveName() { + return true; + } + + @Override + @FxThread + public void setName(@Nullable String name) { + this.name = name; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/VertexBufferTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/VertexBufferTreeNode.java new file mode 100644 index 00000000..f77e99e2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/VertexBufferTreeNode.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.control.tree.node.impl; + +import com.jme3.scene.VertexBuffer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.ObjectUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.Buffer; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; + +/** + * The implementation of the {@link TreeNode} to represent the {@link VertexBuffer} in the editor. + * + * @author JavaSaBr + */ +public class VertexBufferTreeNode extends TreeNode { + + public VertexBufferTreeNode(@NotNull VertexBuffer element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.VERTEX_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_VERTEX_BUFFER + " [" + getElement().getBufferType() + "]"; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var vertexBuffer = getElement(); + var data = vertexBuffer.getData(); + + if (data == null) { + return Array.empty(); + } + + return Array.of(notNull(FACTORY_REGISTRY.createFor(data))); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/ControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/ControlTreeNode.java new file mode 100644 index 00000000..a805d54e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/ControlTreeNode.java @@ -0,0 +1,73 @@ +package com.ss.builder.fx.control.tree.node.impl.control; + +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.RemoveControlAction; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.Named; +import com.ss.editor.extension.scene.control.EditableControl; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.RemoveControlAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link TreeNode} to show a {@link Control} in the tree. + * + * @param the type parameter + * @author JavaSaBr + */ +public class ControlTreeNode extends TreeNode { + + public ControlTreeNode(@NotNull T element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + items.add(new RemoveControlAction(nodeTree, this)); + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.GEAR_16; + } + + @Override + @FxThread + public boolean canCopy() { + return true; + } + + @Override + @FxThread + public boolean canMove() { + return true; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + + var element = getElement(); + + if (element instanceof EditableControl) { + return ((EditableControl) element).getName(); + } else if (element instanceof Named) { + return ((Named) element).getName(); + } + + return element.getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/LightControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/LightControlTreeNode.java new file mode 100644 index 00000000..aac69aaf --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/LightControlTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.control; + +import com.jme3.scene.control.LightControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link TreeNode} to show a {@link LightControl} in the tree. + * + * @author JavaSaBr + */ +public class LightControlTreeNode extends ControlTreeNode { + + public LightControlTreeNode(@NotNull LightControl element, long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_LIGHT_CONTROL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/SkeletonControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/SkeletonControlTreeNode.java new file mode 100644 index 00000000..052dbe31 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/SkeletonControlTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.control; + +import com.jme3.animation.SkeletonControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link SkeletonControl}. + * + * @author JavaSaBr + */ +public class SkeletonControlTreeNode extends ControlTreeNode { + + public SkeletonControlTreeNode(@NotNull SkeletonControl element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SKELETON_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_SKELETON_CONTROL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationClipTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationClipTreeNode.java new file mode 100644 index 00000000..462c4b5d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationClipTreeNode.java @@ -0,0 +1,51 @@ +package com.ss.builder.fx.control.tree.node.impl.control.anim; + +import com.jme3.anim.AnimClip; +import com.jme3.anim.AnimComposer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.ObjectUtils; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link AnimClip}. + * + * @author JavaSaBr + */ +public class AnimationClipTreeNode extends TreeNode { + + public AnimationClipTreeNode(@NotNull AnimClip animClip, long objectId) { + super(animClip, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + var animClip = getElement(); + var animationControlTreeNode = ObjectUtils.notNull((AnimationControlTreeNode) getParent()); + var animComposer = animationControlTreeNode.getElement(); + + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + public @NotNull String getName() { + return getElement().getName(); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.ANIMATION_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationControlTreeNode.java new file mode 100644 index 00000000..e4240a0d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/anim/AnimationControlTreeNode.java @@ -0,0 +1,74 @@ +package com.ss.builder.fx.control.tree.node.impl.control.anim; + +import com.jme3.anim.AnimComposer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link AnimComposer}. + * + * @author JavaSaBr + */ +public class AnimationControlTreeNode extends ControlTreeNode { + + public AnimationControlTreeNode(@NotNull AnimComposer animComposer, long objectId) { + super(animComposer, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + super.fillContextMenu(nodeTree, items); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_ANIM_COMPOSER; + } + + @Override + public @Nullable Image getIcon() { + return Icons.ANIMATION_16; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var animComposer = getElement(); + var animClips = animComposer.getAnimClips(); + + var result = ArrayFactory.>newArray(TreeNode.class, animClips.size()); + + animClips.forEach(animClip -> result.add(FACTORY_REGISTRY.createFor(animClip))); + + result.addAll(super.getChildren(nodeTree)); + + return result; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationAudioTrackTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationAudioTrackTreeNode.java new file mode 100644 index 00000000..2183bdb9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationAudioTrackTreeNode.java @@ -0,0 +1,36 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import com.jme3.animation.AudioTrack; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link AudioTrack}. + * + * @author JavaSaBr + */ +@Deprecated +public class AnimationAudioTrackTreeNode extends AnimationTrackTreeNode { + + public AnimationAudioTrackTreeNode(@NotNull AudioTrack element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + protected @NotNull String computeName() { + var audioTrack = getElement(); + return "Audio track : " + audioTrack.getAudio().getName(); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.AUDIO_16; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationBoneTrackTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationBoneTrackTreeNode.java similarity index 89% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationBoneTrackTreeNode.java rename to src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationBoneTrackTreeNode.java index 46c3a426..12260f90 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationBoneTrackTreeNode.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationBoneTrackTreeNode.java @@ -1,11 +1,12 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.animation.AnimControl; import com.jme3.animation.Bone; import com.jme3.animation.BoneTrack; import com.jme3.animation.Skeleton; -import com.ss.editor.ui.Icons; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.Icons; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,6 +16,7 @@ * * @author JavaSaBr */ +@Deprecated public class AnimationBoneTrackTreeNode extends AnimationTrackTreeNode { /** diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationControlTreeNode.java new file mode 100644 index 00000000..c3941e6a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationControlTreeNode.java @@ -0,0 +1,136 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.LoopMode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.animation.PlaySettingsAction; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.animation.PlaySettingsAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; + +import java.util.Collection; + +/** + * The implementation of node to show {@link AnimControl}. + * + * @author JavaSaBr + */ +@Deprecated +public class AnimationControlTreeNode extends ControlTreeNode { + + /** + * The loop mode. + */ + @NotNull + private LoopMode loopMode; + + /** + * The animation speed. + */ + private float speed; + + public AnimationControlTreeNode(@NotNull AnimControl element, long objectId) { + super(element, objectId); + this.loopMode = LoopMode.Loop; + this.speed = 1.0F; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + items.add(new PlaySettingsAction(nodeTree, this)); + super.fillContextMenu(nodeTree, items); + } + + /** + * Update settings. + * + * @param loopMode the loop mode. + * @param speed the animation speed. + */ + @FxThread + public void updateSettings(@NotNull LoopMode loopMode, float speed) { + this.loopMode = loopMode; + this.speed = speed; + } + + /** + * Gets speed. + * + * @return the animation speed. + */ + @FxThread + public float getSpeed() { + return speed; + } + + /** + * Gets loop mode. + * + * @return the loop mode. + */ + @FxThread + public @NotNull LoopMode getLoopMode() { + return loopMode; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_ANIM_CONTROL; + } + + @Override + public @Nullable Image getIcon() { + return Icons.ANIMATION_16; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var result = ArrayFactory.>newArray(TreeNode.class); + + var animControl = getElement(); + var animationNames = animControl.getAnimationNames(); + animationNames.forEach(name -> result.add(FACTORY_REGISTRY.createFor(animControl.getAnim(name)))); + + result.addAll(super.getChildren(nodeTree)); + + return result; + } + + @Override + @FxThread + public void notifyChildPreAdd(@NotNull TreeNode treeNode) { + + var animationModelNode = (AnimationTreeNode) treeNode; + animationModelNode.setControl(getElement()); + animationModelNode.setControlModelNode(this); + + super.notifyChildPreAdd(treeNode); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationEffectTrackTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationEffectTrackTreeNode.java new file mode 100644 index 00000000..533ce9d4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationEffectTrackTreeNode.java @@ -0,0 +1,36 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import com.jme3.animation.EffectTrack; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link EffectTrack}. + * + * @author JavaSaBr + */ +@Deprecated +public class AnimationEffectTrackTreeNode extends AnimationTrackTreeNode { + + public AnimationEffectTrackTreeNode(@NotNull EffectTrack element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + protected @NotNull String computeName() { + var effectTrack = getElement(); + return "Effect track : " + effectTrack.getEmitter().getName(); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.PARTICLES_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationSpatialTrackTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationSpatialTrackTreeNode.java new file mode 100644 index 00000000..8ef39387 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationSpatialTrackTreeNode.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import com.jme3.animation.SpatialTrack; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link SpatialTrack}. + * + * @author JavaSaBr + */ +@Deprecated +public class AnimationSpatialTrackTreeNode extends AnimationTrackTreeNode { + + public AnimationSpatialTrackTreeNode(@NotNull SpatialTrack element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + protected @NotNull String computeName() { + return "Spatial track"; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.NODE_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTrackTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTrackTreeNode.java new file mode 100644 index 00000000..0c1a34ba --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTrackTreeNode.java @@ -0,0 +1,72 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Track; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link Track}. + * + * @param the type parameter + * @author JavaSaBr + */ +@Deprecated +public abstract class AnimationTrackTreeNode extends TreeNode { + + /** + * The animation control. + */ + @Nullable + private AnimControl control; + + /** + * The cached name. + */ + @Nullable + private String cachedName; + + public AnimationTrackTreeNode(@NotNull T element, long objectId) { + super(element, objectId); + } + + /** + * Set the animation control. + * + * @param control the animation control. + */ + @FxThread + public void setControl(@Nullable AnimControl control) { + this.control = control; + this.cachedName = computeName(); + } + + /** + * Compute name string. + * + * @return the string + */ + @FxThread + protected abstract @NotNull String computeName(); + + @Override + @FromAnyThread + public @NotNull String getName() { + return cachedName; + } + + /** + * Get the animation control. + * + * @return the animation control. + */ + @FxThread + protected @Nullable AnimControl getControl() { + return control; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTreeNode.java new file mode 100644 index 00000000..83ad4ee2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/legacyanim/AnimationTreeNode.java @@ -0,0 +1,253 @@ +package com.ss.builder.fx.control.tree.node.impl.control.legacyanim; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.jme3.animation.Track; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.impl.animation.RenameAnimationNodeOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.action.impl.animation.*; +import com.ss.builder.util.AnimationUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.action.impl.animation.*; +import com.ss.builder.model.undo.impl.animation.RenameAnimationNodeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.AnimationUtils; +import com.ss.rlib.common.util.ArrayUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link Animation}. + * + * @author JavaSaBr + */ +@Deprecated +public class AnimationTreeNode extends TreeNode { + + /** + * The node of an animation control. + */ + @Nullable + private AnimationControlTreeNode controlModelNode; + + /** + * The animation control. + */ + @Nullable + private AnimControl control; + + /** + * The speed. + */ + private float speed; + + /** + * The index of playing animation. + */ + private int channel; + + public AnimationTreeNode(@NotNull Animation element, long objectId) { + super(element, objectId); + this.channel = -1; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + var animation = getElement(); + var controlModelNode = notNull(getControlModelNode()); + var animControl = controlModelNode.getElement(); + + var frameCount = AnimationUtils.getFrameCount(animation); + + if (getChannel() < 0 && animControl.getNumChannels() < 1) { + items.add(new PlayAnimationAction(nodeTree, this)); + items.add(new RemoveAnimationAction(nodeTree, this)); + items.add(new RenameNodeAction(nodeTree, this)); + } else if (getChannel() >= 0 && animControl.getChannel(getChannel()).getSpeed() < 0.0001F) { + items.add(new PlayAnimationAction(nodeTree, this)); + items.add(new StopAnimationAction(nodeTree, this)); + } else if (getChannel() >= 0) { + items.add(new PauseAnimationAction(nodeTree, this)); + items.add(new StopAnimationAction(nodeTree, this)); + } + + if (getChannel() < 0 && frameCount > 0) { + items.add(new ManualExtractSubAnimationAction(nodeTree, this)); + } + + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + + var animation = getElement(); + var tracks = animation.getTracks(); + + return tracks != null && tracks.length > 0 && + nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var animation = getElement(); + var tracks = animation.getTracks(); + + var result = ArrayFactory.>newArray(TreeNode.class, tracks.length); + + ArrayUtils.forEach(tracks, track -> result.add(FACTORY_REGISTRY.createFor(track))); + + return result; + } + + @Override + @FxThread + public boolean canEditName() { + return true; + } + + @Override + @FxThread + public void changeName(@NotNull NodeTree nodeTree, @NotNull String newName) { + + if (StringUtils.equals(getName(), newName)) { + return; + } + + super.changeName(nodeTree, newName); + + var controlModelNode = notNull(getControlModelNode()); + var animControl = controlModelNode.getElement(); + var operation = new RenameAnimationNodeOperation(getName(), newName, animControl); + + notNull(nodeTree.getChangeConsumer()) + .execute(operation); + } + + /** + * Gets control model node. + * + * @return the node of an animation control. + */ + @FxThread + public @Nullable AnimationControlTreeNode getControlModelNode() { + return controlModelNode; + } + + /** + * Sets control model node. + * + * @param controlModelNode the node of an animation control. + */ + @FxThread + public void setControlModelNode(@Nullable AnimationControlTreeNode controlModelNode) { + this.controlModelNode = controlModelNode; + } + + /** + * Gets control. + * + * @return the animation control. + */ + @FxThread + public @Nullable AnimControl getControl() { + return control; + } + + /** + * Sets control. + * + * @param control the animation control. + */ + @FxThread + public void setControl(@Nullable AnimControl control) { + this.control = control; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return getElement().getName(); + } + + /** + * Gets channel. + * + * @return the index of playing animation. + */ + @FxThread + public int getChannel() { + return channel; + } + + /** + * Sets channel. + * + * @param channel the index of playing animation. + */ + @FxThread + public void setChannel(int channel) { + this.channel = channel; + } + + /** + * Gets speed. + * + * @return the speed + */ + @FxThread + public float getSpeed() { + return speed; + } + + /** + * Sets speed. + * + * @param speed the speed + */ + @FxThread + public void setSpeed(float speed) { + this.speed = speed; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + + if (getChannel() < 0) { + return Icons.PLAY_16; + } + + return getSpeed() < 0.0001F ? Icons.PAUSE_16 : Icons.STOP_16; + } + + @Override + @FxThread + public void notifyChildPreAdd(@NotNull TreeNode treeNode) { + var animationTrackModelNode = (AnimationTrackTreeNode) treeNode; + animationTrackModelNode.setControl(getControl()); + super.notifyChildPreAdd(treeNode); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionEventTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionEventTreeNode.java new file mode 100644 index 00000000..2b82bf08 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionEventTreeNode.java @@ -0,0 +1,61 @@ +package com.ss.builder.fx.control.tree.node.impl.control.motion; + +import com.jme3.cinematic.MotionPath; +import com.jme3.cinematic.events.MotionEvent; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link ControlTreeNode} to show a {@link MotionEvent} in the tree. + * + * @author JavaSaBr + */ +public class MotionEventTreeNode extends ControlTreeNode { + + public MotionEventTreeNode(@NotNull final MotionEvent element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_MOTION_CONTROL; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MOTION_16; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + final MotionPath path = getElement().getPath(); + final Array> result = ArrayFactory.newArray(TreeNode.class); + result.add(FACTORY_REGISTRY.createFor(path)); + + return result; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return true; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionPathTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionPathTreeNode.java new file mode 100644 index 00000000..7ef9afc0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/motion/MotionPathTreeNode.java @@ -0,0 +1,70 @@ +package com.ss.builder.fx.control.tree.node.impl.control.motion; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.cinematic.MotionPath; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.PositionTreeNode; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; + +/** + * The implementation of the {@link TreeNode} to show a {@link MotionPath} in the tree. + * + * @author JavaSaBr + */ +public class MotionPathTreeNode extends TreeNode { + + public MotionPathTreeNode(@NotNull final MotionPath element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_MOTION_PATH; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.PATH_16; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + final MotionPath element = getElement(); + final int wayPoints = element.getNbWayPoints(); + + final Array> result = ArrayFactory.newArray(TreeNode.class); + + for (int i = 0; i < wayPoints; i++) { + final PositionTreeNode modelNode = notNull(FACTORY_REGISTRY.createFor(element.getWayPoint(i))); + modelNode.setName(Messages.MODEL_FILE_EDITOR_NODE_WAY_POINT + " #" + (i + 1)); + result.add(modelNode); + } + + return result; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java new file mode 100644 index 00000000..47415265 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java @@ -0,0 +1,39 @@ +package com.ss.builder.fx.control.tree.node.impl.control.physics; + +import com.jme3.bullet.control.BetterCharacterControl; +import com.jme3.bullet.control.CharacterControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link CharacterControl}. + * + * @author JavaSaBr + */ +public class BetterCharacterControlTreeNode extends PhysicsControlTreeNode { + + public BetterCharacterControlTreeNode(@NotNull final BetterCharacterControl element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.CHARACTER_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_CHARACTER_CONTROL; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java similarity index 81% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java rename to src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java index 4db20175..3cb045c7 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java @@ -1,15 +1,19 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics; +package com.ss.builder.fx.control.tree.node.impl.control.physics; import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.control.PhysicsControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.physics.shape.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.physics.shape.*; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.physics.shape.*; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import javafx.collections.ObservableList; diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RagdollControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RagdollControlTreeNode.java new file mode 100644 index 00000000..8356a705 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RagdollControlTreeNode.java @@ -0,0 +1,40 @@ +package com.ss.builder.fx.control.tree.node.impl.control.physics; + +import com.jme3.bullet.control.KinematicRagdollControl; +import com.jme3.bullet.control.VehicleControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link VehicleControl}. + * + * @author JavaSaBr + */ +public class RagdollControlTreeNode extends ControlTreeNode { + + public RagdollControlTreeNode(@NotNull final KinematicRagdollControl element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.DOLL_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_RAGDOLL_CONTROL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java new file mode 100644 index 00000000..58da42fc --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java @@ -0,0 +1,71 @@ +package com.ss.builder.fx.control.tree.node.impl.control.physics; + +import com.jme3.bullet.control.RigidBodyControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.physics.ReactivatePhysicsControlAction; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.physics.ReactivatePhysicsControlAction; +import com.ss.builder.fx.control.tree.NodeTree; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link RigidBodyControl}. + * + * @author JavaSaBr + */ +public class RigidBodyControlTreeNode extends PhysicsControlTreeNode { + + public RigidBodyControlTreeNode(@NotNull final RigidBodyControl element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + + final RigidBodyControl element = getElement(); + + if (element.getMass() == 0F) { + return Icons.STATIC_RIGID_BODY_16; + } + + return Icons.RIGID_BODY_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + + final RigidBodyControl element = getElement(); + + if (element.getMass() == 0F) { + return Messages.MODEL_FILE_EDITOR_NODE_STATIC_RIGID_BODY_CONTROL; + } + + return Messages.MODEL_FILE_EDITOR_NODE_RIGID_BODY_CONTROL; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, + @NotNull final ObservableList items) { + + final RigidBodyControl element = getElement(); + + if (!element.isActive()) { + items.add(new ReactivatePhysicsControlAction(nodeTree, this)); + } + + super.fillContextMenu(nodeTree, items); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java new file mode 100644 index 00000000..5f4bbb7e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java @@ -0,0 +1,54 @@ +package com.ss.builder.fx.control.tree.node.impl.control.physics.vehicle; + +import com.jme3.bullet.control.VehicleControl; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.CreateVehicleWheelAction; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.control.physics.PhysicsControlTreeNode; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.CreateVehicleWheelAction; +import com.ss.builder.fx.control.tree.NodeTree; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link VehicleControl}. + * + * @author JavaSaBr + */ +public class VehicleControlTreeNode extends PhysicsControlTreeNode { + + public VehicleControlTreeNode(@NotNull final VehicleControl element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.VEHICLE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_VEHICLE_CONTROL; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, + @NotNull final ObservableList items) { + + items.add(new CreateVehicleWheelAction(nodeTree, this)); + + super.fillContextMenu(nodeTree, items); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java new file mode 100644 index 00000000..3868dfd1 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java @@ -0,0 +1,56 @@ +package com.ss.builder.fx.control.tree.node.impl.control.physics.vehicle; + +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.RemoveVehicleWheelAction; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.RemoveVehicleWheelAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link VehicleWheel}. + * + * @author JavaSaBr + */ +public class VehicleWheelTreeNode extends TreeNode { + + public VehicleWheelTreeNode(@NotNull final VehicleWheel element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.WHEEL_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final VehicleWheel element = getElement(); + final Spatial wheelSpatial = element.getWheelSpatial(); + return wheelSpatial != null ? Messages.MODEL_FILE_EDITOR_NODE_WHEEL + " [" + wheelSpatial.getName() + "]" : + Messages.MODEL_FILE_EDITOR_NODE_WHEEL; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, + @NotNull final ObservableList items) { + super.fillContextMenu(nodeTree, items); + items.add(new RemoveVehicleWheelAction(nodeTree, this)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/LayersRootTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/LayersRootTreeNode.java new file mode 100644 index 00000000..f47810f7 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/LayersRootTreeNode.java @@ -0,0 +1,84 @@ +package com.ss.builder.fx.control.tree.node.impl.layer; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.layer.LayerNodeTree; +import com.ss.builder.fx.control.tree.action.impl.scene.CreateSceneLayerAction; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.layer.LayerNodeTree; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.fx.control.tree.action.impl.scene.CreateSceneLayerAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The implementation of {@link TreeNode} to present {@link LayersRoot}. + * + * @author JavaSaBr + */ +public class LayersRootTreeNode extends TreeNode { + + public LayersRootTreeNode(@NotNull final LayersRoot element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SCENE_16; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { + items.add(new CreateSceneLayerAction(nodeTree, this)); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final LayersRoot element = getElement(); + final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); + final SceneNode sceneNode = changeConsumer.getCurrentModel(); + return sceneNode.getName(); + } + + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + final LayersRoot element = getElement(); + final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); + final SceneNode sceneNode = changeConsumer.getCurrentModel(); + final List layers = sceneNode.getLayers(); + + final Array> result = ArrayFactory.newArray(TreeNode.class); + layers.forEach(layer -> result.add(FACTORY_REGISTRY.createFor(layer))); + + return result; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return nodeTree instanceof LayerNodeTree; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/SceneLayerTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/SceneLayerTreeNode.java new file mode 100644 index 00000000..e82f1f3c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/layer/SceneLayerTreeNode.java @@ -0,0 +1,180 @@ +package com.ss.builder.fx.control.tree.node.impl.layer; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.RenameNodeOperation; +import com.ss.builder.model.undo.impl.scene.ChangeVisibleSceneLayerOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.action.impl.scene.RemoveSceneLayerAction; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.model.undo.impl.RenameNodeOperation; +import com.ss.builder.model.undo.impl.scene.ChangeVisibleSceneLayerOperation; +import com.ss.builder.fx.control.tree.action.impl.scene.RemoveSceneLayerAction; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.HideableNode; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link NodeTreeNode} for representing the {@link SceneLayer} in the editor. + * + * @author JavaSaBr + */ +public class SceneLayerTreeNode extends TreeNode implements HideableNode { + + public SceneLayerTreeNode(@NotNull final SceneLayer element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { + super.fillContextMenu(nodeTree, items); + + final SceneLayer layer = getElement(); + + if (!layer.isBuiltIn()) { + items.add(new RenameNodeAction(nodeTree, this)); + items.add(new RemoveSceneLayerAction(nodeTree, this)); + } + } + + @Override + @FxThread + public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { + + final SceneLayer element = getElement(); + + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RenameNodeOperation(element.getName(), newName, element)); + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return true; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + final SceneLayer element = getElement(); + + final Array> result = ArrayFactory.newArray(TreeNode.class); + final ModelChangeConsumer changeConsumer = (ModelChangeConsumer) notNull(nodeTree.getChangeConsumer()); + + final Spatial currentModel = changeConsumer.getCurrentModel(); + currentModel.depthFirstTraversal(spatial -> { + final SceneLayer layer = SceneLayer.getLayer(spatial); + if(layer == element) { + result.add(FACTORY_REGISTRY.createFor(spatial)); + } + }); + + return result; + } + + @Override + @FxThread + public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { + final Object element = treeNode.getElement(); + return element instanceof Spatial && SceneLayer.getLayer((Spatial) element) != getElement(); + } + + @Override + @FxThread + public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, + final boolean isCopy) { + + final SceneLayer targetLayer = getElement(); + + if (object instanceof Spatial && !isCopy) { + + final Spatial spatial = (Spatial) object; + final SceneLayer currentLayer = SceneLayer.getLayer(spatial); + + final PropertyOperation operation = + new PropertyOperation<>(spatial, SceneLayer.KEY, targetLayer, currentLayer); + + operation.setApplyHandler((sp, layer) -> SceneLayer.setLayer(layer, sp)); + + changeConsumer.execute(operation); + } + + super.accept(changeConsumer, object, isCopy); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final String name = getElement().getName(); + return name == null ? "name is null" : name; + } + + @Override + @FxThread + public boolean canEditName() { + return !getElement().isBuiltIn(); + } + + @Override + @FxThread + public boolean canMove() { + return false; + } + + @Override + @FxThread + public boolean canCopy() { + return false; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.LAYERS_16; + } + + @Override + public boolean isHided() { + return !getElement().isShowed(); + } + + @Override + @FxThread + public void show(@NotNull final NodeTree nodeTree) { + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new ChangeVisibleSceneLayerOperation(getElement(), true)); + } + + @Override + @FxThread + public void hide(@NotNull final NodeTree nodeTree) { + final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + consumer.execute(new ChangeVisibleSceneLayerOperation(getElement(), false)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/AmbientLightTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/AmbientLightTreeNode.java new file mode 100644 index 00000000..6857367f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/AmbientLightTreeNode.java @@ -0,0 +1,43 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import com.jme3.light.AmbientLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.scene.image.Image; +import com.ss.rlib.common.util.StringUtils; + +/** + * The implementation of {@link LightTreeNode} to present ambient lights. + * + * @author JavaSaBr + */ +public class AmbientLightTreeNode extends LightTreeNode { + + public AmbientLightTreeNode(@NotNull final AmbientLight element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.AMBIENT_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final AmbientLight element = getElement(); + final String name = element.getName(); + return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_AMBIENT_LIGHT : name; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/DirectionalLightTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/DirectionalLightTreeNode.java new file mode 100644 index 00000000..33814b9f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/DirectionalLightTreeNode.java @@ -0,0 +1,41 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import com.jme3.light.DirectionalLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of {@link LightTreeNode} to present direction lights. + * + * @author JavaSaBr + */ +public class DirectionalLightTreeNode extends LightTreeNode { + + public DirectionalLightTreeNode(@NotNull final DirectionalLight element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SUN_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final DirectionalLight element = getElement(); + final String name = element.getName(); + return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_DIRECTION_LIGHT : name; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightProbeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightProbeTreeNode.java new file mode 100644 index 00000000..1308f483 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightProbeTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import com.jme3.light.LightProbe; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The tree node to present {@link LightProbe} + * + * @author JavaSaBr + */ +public class LightProbeTreeNode extends TreeNode { + + public LightProbeTreeNode(@NotNull final LightProbe element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_LIGHT_PROBE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightTreeNode.java new file mode 100644 index 00000000..617b5d39 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/LightTreeNode.java @@ -0,0 +1,73 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.light.Light; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.RenameLightOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.RemoveLightAction; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.RemoveLightAction; +import com.ss.builder.model.undo.impl.RenameLightOperation; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.StringUtils; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of {@link TreeNode} to present lights. + * + * @param the type parameter + * @author JavaSaBr + */ +public class LightTreeNode extends TreeNode { + + public LightTreeNode(@NotNull final T element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final T element = getElement(); + final String name = element.getName(); + return StringUtils.isEmpty(name) ? element.getClass().getSimpleName() : name; + } + + @Override + @FxThread + public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { + final T element = getElement(); + final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + final String currentName = element.getName(); + consumer.execute(new RenameLightOperation(currentName == null ? "" : currentName, newName, element)); + } + + @Override + @FxThread + public boolean canEditName() { + return true; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.LIGHT_16; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { + items.add(new RemoveLightAction(nodeTree, this)); + super.fillContextMenu(nodeTree, items); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/PointLightTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/PointLightTreeNode.java new file mode 100644 index 00000000..f1bba1c0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/PointLightTreeNode.java @@ -0,0 +1,41 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import com.jme3.light.PointLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of {@link LightTreeNode} to present point lights. + * + * @author JavaSaBr + */ +public class PointLightTreeNode extends LightTreeNode { + + public PointLightTreeNode(@NotNull final PointLight element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.POINT_LIGHT_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final PointLight element = getElement(); + final String name = element.getName(); + return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_POINT_LIGHT : name; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/SpotLightTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/SpotLightTreeNode.java new file mode 100644 index 00000000..598c759a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/light/SpotLightTreeNode.java @@ -0,0 +1,41 @@ +package com.ss.builder.fx.control.tree.node.impl.light; + +import com.jme3.light.SpotLight; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.rlib.common.util.StringUtils; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of {@link LightTreeNode} to present spot lights. + * + * @author JavaSaBr + */ +public class SpotLightTreeNode extends LightTreeNode { + + public SpotLightTreeNode(@NotNull final SpotLight element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.LAMP_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final SpotLight element = getElement(); + final String name = element.getName(); + return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_SPOT_LIGHT : name; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java new file mode 100644 index 00000000..5a41dc5e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.ColorsSettings; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.ColorsSettings; +import org.jetbrains.annotations.NotNull; + +/** + * The base presentation of colors settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @author JavaSaBr + */ +public class ColorsSettingsTreeNode extends MaterialSettingsTreeNode { + + public ColorsSettingsTreeNode(@NotNull final ColorsSettings element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MATERIAL_SETTINGS_COLORS; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java new file mode 100644 index 00000000..0b44b061 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java @@ -0,0 +1,31 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.MaterialSettings; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.MaterialSettings; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base presentation of material settings in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @param the type of material settings. + * @author JavaSaBr + */ +public class MaterialSettingsTreeNode extends TreeNode { + + public MaterialSettingsTreeNode(@NotNull final T element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.INFLUENCER_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java new file mode 100644 index 00000000..03687dd7 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.OtherSettings; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.OtherSettings; +import org.jetbrains.annotations.NotNull; + +/** + * The base presentation of other settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @author JavaSaBr + */ +public class OtherSettingsTreeNode extends MaterialSettingsTreeNode { + + public OtherSettingsTreeNode(@NotNull final OtherSettings element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MATERIAL_SETTINGS_OTHER; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java new file mode 100644 index 00000000..96296c0a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.RenderSettings; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.RenderSettings; +import org.jetbrains.annotations.NotNull; + +/** + * The base presentation of render settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @author JavaSaBr + */ +public class RenderSettingsTreeNode extends MaterialSettingsTreeNode { + + public RenderSettingsTreeNode(@NotNull final RenderSettings element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MATERIAL_SETTINGS_RENDER; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java new file mode 100644 index 00000000..e1f508fa --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java @@ -0,0 +1,54 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.node.material.*; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.*; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +/** + * The base presentation of root settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @author JavaSaBr + */ +public class RootMaterialSettingsTreeNode extends MaterialSettingsTreeNode { + + public RootMaterialSettingsTreeNode(@NotNull final RootMaterialSettings element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + final RootMaterialSettings settings = getElement(); + + final Array> children = ArrayFactory.newArray(TreeNode.class); + children.add(FACTORY_REGISTRY.createFor(new TexturesSettings(settings.getMaterial()))); + children.add(FACTORY_REGISTRY.createFor(new ColorsSettings(settings.getMaterial()))); + children.add(FACTORY_REGISTRY.createFor(new RenderSettings(settings.getMaterial()))); + children.add(FACTORY_REGISTRY.createFor(new OtherSettings(settings.getMaterial()))); + + return children; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MATERIAL_SETTINGS_MAIN; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return true; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java new file mode 100644 index 00000000..89b0014b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java @@ -0,0 +1,27 @@ +package com.ss.builder.fx.control.tree.node.impl.material.settings; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.TexturesSettings; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.node.material.TexturesSettings; +import org.jetbrains.annotations.NotNull; + +/** + * The base presentation of textures settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. + * + * @author JavaSaBr + */ +public class TexturesSettingsTreeNode extends MaterialSettingsTreeNode { + + public TexturesSettingsTreeNode(@NotNull final TexturesSettings element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MATERIAL_SETTINGS_TEXTURES; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java new file mode 100644 index 00000000..f0aced00 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of node to show {@link BoxCollisionShape}. + * + * @author JavaSaBr + */ +public class BoxCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public BoxCollisionShapeTreeNode(@NotNull final BoxCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_BOX_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java new file mode 100644 index 00000000..66061bc9 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link CapsuleCollisionShape}. + * + * @author JavaSaBr + */ +public class CapsuleCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public CapsuleCollisionShapeTreeNode(@NotNull final CapsuleCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.CAPSULE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_CAPSULE_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java similarity index 75% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java rename to src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java index e9afbe1e..a872a2d0 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ChildCollisionShapeTreeNode.java @@ -1,13 +1,17 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; +package com.ss.builder.fx.control.tree.node.impl.physics.shape; import com.jme3.bullet.collision.shapes.CollisionShape; import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import javafx.scene.image.Image; diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java new file mode 100644 index 00000000..43c5d128 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java @@ -0,0 +1,39 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link TreeNode} to show a {@link CollisionShape} in the tree. + * + * @param the type parameter + * @author JavaSaBr + */ +public class CollisionShapeTreeNode extends TreeNode { + + public CollisionShapeTreeNode(@NotNull final T element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.GEOMETRY_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final T element = getElement(); + return element.getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java similarity index 76% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java rename to src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java index 09a8b862..842b7b11 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ComputedCollisionShapeTreeNode.java @@ -1,13 +1,17 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; +package com.ss.builder.fx.control.tree.node.impl.physics.shape; import com.jme3.bullet.collision.shapes.CompoundCollisionShape; import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java new file mode 100644 index 00000000..27f349a2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.ConeCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link ConeCollisionShape}. + * + * @author JavaSaBr + */ +public class ConeCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public ConeCollisionShapeTreeNode(@NotNull final ConeCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.CONE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_CONE_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java new file mode 100644 index 00000000..a3c0a8ad --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.CylinderCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link CylinderCollisionShape}. + * + * @author JavaSaBr + */ +public class CylinderCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public CylinderCollisionShapeTreeNode(@NotNull final CylinderCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.CYLINDER_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_CYLINDER_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java new file mode 100644 index 00000000..f2119d0b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.GImpactCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link GImpactCollisionShape}. + * + * @author JavaSaBr + */ +public class GImpactCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public GImpactCollisionShapeTreeNode(@NotNull final GImpactCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_GIMPACT_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java new file mode 100644 index 00000000..a408beff --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link HeightfieldCollisionShape}. + * + * @author JavaSaBr + */ +public class HeightFieldCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public HeightFieldCollisionShapeTreeNode(@NotNull final HeightfieldCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.TERRAIN_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_HEIGHT_FIELD_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java new file mode 100644 index 00000000..2a243847 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.HullCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link HullCollisionShape}. + * + * @author JavaSaBr + */ +public class HullCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public HullCollisionShapeTreeNode(@NotNull final HullCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_HULL_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java new file mode 100644 index 00000000..cb67abb2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link MeshCollisionShape}. + * + * @author JavaSaBr + */ +public class MeshCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public MeshCollisionShapeTreeNode(@NotNull final MeshCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_MESH_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java new file mode 100644 index 00000000..316082e5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.PlaneCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link PlaneCollisionShape}. + * + * @author JavaSaBr + */ +public class PlaneCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public PlaneCollisionShapeTreeNode(@NotNull final PlaneCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.PLANE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PLANE_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java new file mode 100644 index 00000000..38122591 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.physics.shape; + +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of node to show {@link SphereCollisionShape}. + * + * @author JavaSaBr + */ +public class SphereCollisionShapeTreeNode extends CollisionShapeTreeNode { + + public SphereCollisionShapeTreeNode(@NotNull final SphereCollisionShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SPHERE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_SPHERE_COLLISION_SHAPE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStateTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStateTreeNode.java new file mode 100644 index 00000000..a565f874 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStateTreeNode.java @@ -0,0 +1,37 @@ +package com.ss.builder.fx.control.tree.node.impl.scene; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The node to present {@link SceneAppState} in the scene model tree. + * + * @author JavaSaBr + */ +public class SceneAppStateTreeNode extends TreeNode { + + public SceneAppStateTreeNode(@NotNull final SceneAppState element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return getElement().getName(); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SETTINGS_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStatesTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStatesTreeNode.java new file mode 100644 index 00000000..01f65d6c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneAppStatesTreeNode.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.control.tree.node.impl.scene; + +import com.jme3.util.SafeArrayList; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.scene.SceneAppStatesNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.scene.SceneAppStatesNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The node to present scene app states node. + * + * @author JavaSaBr + */ +public class SceneAppStatesTreeNode extends TreeNode { + + public SceneAppStatesTreeNode(@NotNull final SceneAppStatesNode element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SETTINGS_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.SCENE_FILE_EDITOR_TOOL_APP_STATES; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return nodeTree instanceof SceneNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + if (!(nodeTree instanceof SceneNodeTree)) { + return super.getChildren(nodeTree); + } + + final @NotNull SafeArrayList appStates = getElement().getAppStates(); + + final Array> result = ArrayFactory.newArray(TreeNode.class); + appStates.forEach(appState -> result.add(FACTORY_REGISTRY.createFor(appState))); + + return result; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFilterTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFilterTreeNode.java new file mode 100644 index 00000000..f19a3e80 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFilterTreeNode.java @@ -0,0 +1,37 @@ +package com.ss.builder.fx.control.tree.node.impl.scene; + +import com.jme3.post.Filter; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The node to present {@link Filter} in the scene model tree. + * + * @author JavaSaBr + */ +public class SceneFilterTreeNode extends TreeNode { + + public SceneFilterTreeNode(@NotNull final Filter element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return getElement().getName(); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.FILTER_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFiltersTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFiltersTreeNode.java new file mode 100644 index 00000000..91d88559 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneFiltersTreeNode.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.control.tree.node.impl.scene; + +import com.jme3.util.SafeArrayList; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The node to present scene filters node. + * + * @author JavaSaBr + */ +public class SceneFiltersTreeNode extends TreeNode { + + public SceneFiltersTreeNode(@NotNull final SceneFiltersNode element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.FILTER_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.SCENE_FILE_EDITOR_NODE_FILTERS; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull final NodeTree nodeTree) { + return nodeTree instanceof SceneNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { + + if (!(nodeTree instanceof SceneNodeTree)) { + return super.getChildren(nodeTree); + } + + final SafeArrayList filters = getElement().getFilters(); + + final Array> result = ArrayFactory.newArray(TreeNode.class); + filters.forEach(sceneFilter -> result.add(FACTORY_REGISTRY.createFor(sceneFilter.get()))); + + return result; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneNodeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneNodeTreeNode.java new file mode 100644 index 00000000..bb075efe --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/scene/SceneNodeTreeNode.java @@ -0,0 +1,104 @@ +package com.ss.builder.fx.control.tree.node.impl.scene; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.model.scene.SceneFiltersNode; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.RenameNodeAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link NodeTreeNode} for representing the {@link SceneNode} in the editor. + * + * @author JavaSaBr + */ +public class SceneNodeTreeNode extends NodeTreeNode { + + public SceneNodeTreeNode(@NotNull SceneNode element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + if (!(nodeTree instanceof ModelNodeTree)) { + return; + } + + createCreationMenu(nodeTree) + .ifPresent(items::add); + + items.add(new RenameNodeAction(nodeTree, this)); + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return super.hasChildren(nodeTree) || nodeTree instanceof SceneNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + if (nodeTree instanceof ModelNodeTree) { + return super.getChildren(nodeTree); + } else if (!(nodeTree instanceof SceneNodeTree)) { + return Array.empty(); + } + + var sceneNode = getElement(); + + //TODO to add other children + var result = ArrayFactory.>newArray(TreeNode.class); + result.add(FACTORY_REGISTRY.createFor(new SceneFiltersNode(sceneNode))); + + return result; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SCENE_16; + } + + @Override + @FxThread + public boolean canMove() { + return false; + } + + @Override + @FxThread + public boolean canAccept(@NotNull TreeNode treeNode, boolean isCopy) { + return false; + } + + @Override + @FxThread + public boolean canCopy() { + return false; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java new file mode 100644 index 00000000..213e0f85 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java @@ -0,0 +1,29 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link SpatialTreeNode} for representing the {@link Node} in the editor. + * + * @author vp -byte + */ +public class AssetLinkNodeTreeNode extends NodeTreeNode { + + public AssetLinkNodeTreeNode(@NotNull AssetLinkNode element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.LINKED_NODE_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AudioTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AudioTreeNode.java new file mode 100644 index 00000000..caf0dd77 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/AudioTreeNode.java @@ -0,0 +1,63 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; +import com.jme3.audio.AudioSource; +import com.jme3.audio.AudioSource.Status; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.audio.PlayAudioNodeAction; +import com.ss.builder.fx.control.tree.action.impl.audio.StopAudioNodeAction; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.audio.PlayAudioNodeAction; +import com.ss.builder.fx.control.tree.action.impl.audio.StopAudioNodeAction; +import com.ss.builder.fx.control.tree.NodeTree; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; + +/** + * The implementation of the {@link NodeTreeNode} for representing the {@link AudioNode} in the editor. + * + * @author JavaSaBr + */ +public class AudioTreeNode extends NodeTreeNode { + + public AudioTreeNode(@NotNull AudioNode element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + if (!(nodeTree instanceof ModelNodeTree)) { + return; + } + + var element = getElement(); + var audioData = element.getAudioData(); + var status = element.getStatus(); + + if (audioData != null && status != Status.Playing) { + items.add(new PlayAudioNodeAction(nodeTree, this)); + } else if (audioData != null) { + items.add(new StopAudioNodeAction(nodeTree, this)); + } + + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.AUDIO_16; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/GeometryTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/GeometryTreeNode.java new file mode 100644 index 00000000..d228bafa --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/GeometryTreeNode.java @@ -0,0 +1,122 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.ss.builder.Messages; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.action.impl.TangentGeneratorAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.GenerateLoDAction; +import com.ss.builder.Messages; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.TangentGeneratorAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.GenerateLoDAction; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.scene.control.Menu; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link SpatialTreeNode} to represent the {@link Geometry} in the editor. + * + * @param the type of geometry. + * @author JavaSaBr + */ +public class GeometryTreeNode extends SpatialTreeNode { + + public GeometryTreeNode(@NotNull T element, long objectId) { + super(element, objectId); + } + + @Override + public @Nullable Image getIcon() { + return Icons.GEOMETRY_16; + } + + @Override + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + if (!(nodeTree instanceof ModelNodeTree)) { + return Array.empty(); + } + + var result = ArrayFactory.>newArray(TreeNode.class); + + var geometry = getElement(); + var mesh = geometry.getMesh(); + var material = geometry.getMaterial(); + + if (mesh != null) { + result.add(FACTORY_REGISTRY.createFor(mesh)); + } + + result.add(FACTORY_REGISTRY.createFor(material)); + result.addAll(super.getChildren(nodeTree)); + + return result; + } + + @Override + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + + var toolActions = new Menu(Messages.MODEL_NODE_TREE_ACTION_TOOLS, + new ImageView(Icons.INFLUENCER_16)); + + toolActions.getItems() + .addAll(new TangentGeneratorAction(nodeTree, this), + new GenerateLoDAction(nodeTree, this)); + + return Optional.of(toolActions); + } + + @Override + public void add(@NotNull TreeNode child) { + super.add(child); + + if (child instanceof MeshTreeNode) { + getElement().setMesh((Mesh) child.getElement()); + } + } + + @Override + public boolean canAccept(@NotNull TreeNode treeNode, boolean isCopy) { + var element = treeNode.getElement(); + return (element instanceof Material && isCopy) || super.canAccept(treeNode, isCopy); + } + + @Override + public void accept(@NotNull ChangeConsumer changeConsumer, @NotNull Object object, boolean isCopy) { + + var geometry = getElement(); + + if (object instanceof Material) { + + var material = (Material) object; + + if (isCopy) { + + var clone = material.clone(); + var operation = new PropertyOperation(geometry, + "Material", clone, geometry.getMaterial()); + operation.setApplyHandler(Geometry::setMaterial); + + changeConsumer.execute(operation); + } + } + + super.accept(changeConsumer, object, isCopy); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MaterialTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MaterialTreeNode.java new file mode 100644 index 00000000..666961a4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MaterialTreeNode.java @@ -0,0 +1,83 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.material.Material; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.MakeAsEmbeddedMaterialAction; +import com.ss.builder.fx.control.tree.action.impl.SaveAsMaterialAction; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.MakeAsEmbeddedMaterialAction; +import com.ss.builder.fx.control.tree.action.impl.SaveAsMaterialAction; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.util.NodeUtils; +import javafx.collections.ObservableList; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link TreeNode} to represent the {@link Material} in the editor. + * + * @author JavaSaBr + */ +public class MaterialTreeNode extends TreeNode { + + public MaterialTreeNode(@NotNull Material element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MATERIAL_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_MATERIAL; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + super.fillContextMenu(nodeTree, items); + + var material = getElement(); + var parent = notNull(getParent()); + var parentElement = parent.getElement(); + var linkNode = parentElement instanceof Spatial ? + NodeUtils.findParent((Spatial) parentElement, AssetLinkNode.class::isInstance) : null; + + if (linkNode == null) { + items.add(new SaveAsMaterialAction(nodeTree, this)); + } + + if (material.getKey() != null) { + items.add(new MakeAsEmbeddedMaterialAction(nodeTree, this)); + } + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return false; + } + + @Override + @FxThread + public boolean canCopy() { + return true; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MeshTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MeshTreeNode.java new file mode 100644 index 00000000..6b7fdb05 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/MeshTreeNode.java @@ -0,0 +1,69 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.util.IntMap; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; + +/** + * The implementation of the {@link TreeNode} to represent the {@link Mesh} in the editor. + * + * @author JavaSaBr + */ +public class MeshTreeNode extends TreeNode { + + public MeshTreeNode(@NotNull Mesh element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.MESH_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_MESH; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var element = getElement(); + var buffers = element.getBuffers(); + var result = ArrayFactory.>newArray(TreeNode.class, buffers.size()); + + buffers.forEach(entry -> result.add(FACTORY_REGISTRY.createFor(entry.getValue()))); + + return result; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return true; + } + + @Override + @FxThread + public boolean canCopy() { + return true; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/NodeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/NodeTreeNode.java new file mode 100644 index 00000000..53c0e960 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/NodeTreeNode.java @@ -0,0 +1,344 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import static com.ss.builder.util.EditorUtils.*; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.asset.ModelKey; +import com.jme3.effect.ParticleEmitter; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.model.undo.impl.MoveChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.*; +import com.ss.builder.fx.control.tree.action.impl.audio.CreateAudioNodeAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateBoxAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateQuadAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateSphereAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateAmbientLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateDirectionLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreatePointLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateSpotLightAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.CreateParticleEmitterAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; +import com.ss.builder.fx.control.tree.action.impl.terrain.CreateTerrainAction; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.model.undo.impl.MoveChildOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.*; +import com.ss.builder.fx.control.tree.action.impl.audio.CreateAudioNodeAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateBoxAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateQuadAction; +import com.ss.builder.fx.control.tree.action.impl.geometry.CreateSphereAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateAmbientLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateDirectionLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreatePointLightAction; +import com.ss.builder.fx.control.tree.action.impl.light.CreateSpotLightAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.CreateParticleEmitterAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; +import com.ss.builder.fx.control.tree.action.impl.terrain.CreateTerrainAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.Dragboard; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +/** + * The implementation of the {@link SpatialTreeNode} for representing the {@link Node} in the editor. + * + * @param the node's type. + * @author JavaSaBr + */ +public class NodeTreeNode extends SpatialTreeNode { + + @FunctionalInterface + public interface ChildrenFilter { + + @FxThread + boolean isNeedExclude(@NotNull Node node, @NotNull Spatial spatial); + } + + @FunctionalInterface + public interface ParticleEmitterFinder { + + @FxThread + boolean isExist(@NotNull Node node); + } + + /** + * @see ParticleEmitterFinder + */ + public static final String EP_PARTICLE_EMITTER_FILTERS = "NodeTreeNode#particleEmitterFinders"; + + /** + * @see ChildrenFilter + */ + public static final String EP_CHILDREN_FILTERS = "NodeTreeNode#childrenFilters"; + + private static final ExtensionPoint PARTICLE_EMITTER_FINDERS = + ExtensionPointManager.register(EP_PARTICLE_EMITTER_FILTERS); + + private static final ExtensionPoint CHILDREN_FILTERS = + ExtensionPointManager.register(EP_CHILDREN_FILTERS); + + public NodeTreeNode(@NotNull T element, long objectId) { + super(element, objectId); + } + + @Override + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + var toolMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_TOOLS, new ImageView(Icons.INFLUENCER_16)); + toolMenu.getItems().addAll(new OptimizeGeometryAction(nodeTree, this)); + return Optional.of(toolMenu); + } + + @Override + @FxThread + protected @NotNull Optional createCreationMenu(@NotNull NodeTree nodeTree) { + + var menuOptional = super.createCreationMenu(nodeTree); + + if (!menuOptional.isPresent()) { + return menuOptional; + } + + var createPrimitiveMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE, + new ImageView(Icons.ADD_12)); + + createPrimitiveMenu.getItems() + .addAll(new CreateBoxAction(nodeTree, this), + new CreateSphereAction(nodeTree, this), + new CreateQuadAction(nodeTree, this)); + + var addLightMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_LIGHT, + new ImageView(Icons.ADD_12)); + + addLightMenu.getItems() + .addAll(new CreateSpotLightAction(nodeTree, this), + new CreatePointLightAction(nodeTree, this), + new CreateAmbientLightAction(nodeTree, this), + new CreateDirectionLightAction(nodeTree, this)); + + var resultMenu = menuOptional.get(); + resultMenu.getItems() + .addAll(new CreateNodeAction(nodeTree, this), + new LoadModelAction(nodeTree, this), + new LinkModelAction(nodeTree, this), + new CreateSkyAction(nodeTree, this), + new CreateEditableSkyAction(nodeTree, this), + new CreateParticleEmitterAction(nodeTree, this), + new CreateAudioNodeAction(nodeTree, this), + new CreateTerrainAction(nodeTree, this), + createPrimitiveMenu, + addLightMenu); + + return menuOptional; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + if (!(nodeTree instanceof ModelNodeTree)) { + return; + } + + var element = getElement(); + var emitter = NodeUtils.findSpatial(element, ParticleEmitter.class::isInstance); + + if (emitter != null || PARTICLE_EMITTER_FINDERS.anyMatch(element, ParticleEmitterFinder::isExist)) { + items.add(new ResetParticleEmittersAction(nodeTree, this)); + } + + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var element = getElement(); + var result = ArrayFactory.>newArray(TreeNode.class); + var children = getSpatialChildren(); + + for (var child : children) { + if (!CHILDREN_FILTERS.anyMatch(element, child, ChildrenFilter::isNeedExclude)) { + result.add(FACTORY_REGISTRY.createFor(child)); + } + } + + result.addAll(super.getChildren(nodeTree)); + + return result; + } + + /** + * Get the children spatial. + * + * @return the children spatial. + */ + @FxThread + protected @NotNull List getSpatialChildren() { + return getElement().getChildren(); + } + + @Override + @FxThread + public boolean canAccept(@NotNull TreeNode treeNode, boolean isCopy) { + + if (treeNode == this) { + return false; + } + + var element = treeNode.getElement(); + if (element instanceof Spatial) { + return GeomUtils.canAttach(getElement(), (Spatial) element, isCopy); + } + + return super.canAccept(treeNode, isCopy); + } + + @Override + @FxThread + public void accept(@NotNull ChangeConsumer changeConsumer, @NotNull Object object, boolean isCopy) { + + var newParent = getElement(); + + if (object instanceof Spatial) { + + var spatial = (Spatial) object; + + if (isCopy) { + + var clone = spatial.clone(); + var layer = SceneLayer.getLayer(spatial); + + if (layer != null) { + SceneLayer.setLayer(layer, clone); + } + + changeConsumer.execute(new AddChildOperation(clone, newParent, true)); + + } else { + var parent = spatial.getParent(); + var childIndex = parent.getChildIndex(spatial); + changeConsumer.execute(new MoveChildOperation(spatial, parent, newParent, childIndex)); + } + } + + super.accept(changeConsumer, object, isCopy); + } + + @Override + @FxThread + public void add(@NotNull TreeNode child) { + super.add(child); + + var node = getElement(); + var toAdd = child.getElement(); + + if (toAdd instanceof Spatial) { + node.attachChildAt((Spatial) toAdd, 0); + } + } + + @Override + @FxThread + public void remove(@NotNull TreeNode child) { + super.remove(child); + + var node = getElement(); + var toRemove = child.getElement(); + + if (toRemove instanceof Spatial) { + node.detachChild((Spatial) toRemove); + } + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.NODE_16; + } + + @Override + @FxThread + public boolean canAcceptExternal(@NotNull Dragboard dragboard) { + return UiUtils.isHasFile(dragboard, FileExtensions.JME_OBJECT); + } + + @Override + @FxThread + public void acceptExternal(@NotNull Dragboard dragboard, @NotNull ChangeConsumer consumer) { + UiUtils.handleDroppedFile(dragboard, getElement(), consumer, this::dropExternalObject); + } + + /** + * Add the external object to this node. + * + * @param node this node. + * @param cons the change consumer. + * @param path the path to the external object. + */ + @FxThread + protected void dropExternalObject( + @NotNull T node, + @NotNull ChangeConsumer cons, + @NotNull Path path + ) { + + var defaultLayer = EditorUtils.getDefaultLayer(cons); + var assetFile = notNull(EditorUtils.getAssetFile(path), "Not found asset file for " + path); + var assetPath = EditorUtils.toAssetPath(assetFile); + var modelKey = new ModelKey(assetPath); + + var assetManager = EditorUtils.getAssetManager(); + var loadedModel = assetManager.loadModel(assetPath); + var assetLinkNode = new AssetLinkNode(modelKey); + assetLinkNode.attachLinkedChild(loadedModel, modelKey); + + if (defaultLayer != null) { + SceneLayer.setLayer(defaultLayer, loadedModel); + } + + cons.execute(new AddChildOperation(assetLinkNode, node)); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/SpatialTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/SpatialTreeNode.java new file mode 100644 index 00000000..62ea2b37 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/SpatialTreeNode.java @@ -0,0 +1,378 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial; + +import static com.ss.builder.Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL; +import static com.ss.builder.Messages.MODEL_NODE_TREE_ACTION_CREATE; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_MODEL_NODE; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.light.Light; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.model.undo.impl.MoveControlOperation; +import com.ss.builder.model.undo.impl.RenameNodeOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.action.impl.AddUserDataAction; +import com.ss.builder.fx.control.tree.action.impl.DisableAllControlsAction; +import com.ss.builder.fx.control.tree.action.impl.EnableAllControlsAction; +import com.ss.builder.fx.control.tree.action.impl.RemoveNodeAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateCustomControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateLightControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateMotionControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateCharacterControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateRigidBodyControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateStaticRigidBodyControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.CreateVehicleControlAction; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.editor.extension.scene.InvisibleObject; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.model.undo.impl.MoveControlOperation; +import com.ss.builder.model.undo.impl.RenameNodeOperation; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.action.impl.AddUserDataAction; +import com.ss.builder.fx.control.tree.action.impl.DisableAllControlsAction; +import com.ss.builder.fx.control.tree.action.impl.EnableAllControlsAction; +import com.ss.builder.fx.control.tree.action.impl.RemoveNodeAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateCustomControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateLightControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.CreateMotionControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateCharacterControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateRigidBodyControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.CreateStaticRigidBodyControlAction; +import com.ss.builder.fx.control.tree.action.impl.control.physics.vehicle.CreateVehicleControlAction; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.control.tree.node.impl.control.ControlTreeNode; +import com.ss.builder.fx.control.tree.node.impl.light.LightTreeNode; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link TreeNode} to represent a {@link Spatial} in an editor. + * + * @param the type of {@link Spatial}. + * @author JavaSaBr + */ +public class SpatialTreeNode extends TreeNode { + + @FunctionalInterface + public interface ActionFactory { + + @FxThread + @Nullable MenuItem create(@NotNull SpatialTreeNode treeNode, @NotNull NodeTree tree); + } + + /** + * @see ActionFactory + */ + public static final String EP_CREATION_ACTION_FACTORIES = "SpatialTreeNode#creationActionFactories"; + + /** + * @see ActionFactory + */ + public static final String EP_CREATION_CONTROL_ACTION_FACTORIES = "SpatialTreeNode#creationControlActionFactories"; + + private static final ExtensionPoint CREATION_ACTION_FACTORIES = + ExtensionPointManager.register(EP_CREATION_ACTION_FACTORIES); + + private static final ExtensionPoint CREATION_CONTROL_ACTION_FACTORIES = + ExtensionPointManager.register(EP_CREATION_CONTROL_ACTION_FACTORIES); + + protected SpatialTreeNode(@NotNull T element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + if (!(nodeTree instanceof ModelNodeTree)) { + return; + } + + var element = getElement(); + var linkNode = NodeUtils.findParent(element, + AssetLinkNode.class::isInstance); + + if (linkNode == null) { + + createCreationMenu(nodeTree).stream() + .peek(this::sort) + .forEach(items::add); + + createToolMenu(nodeTree).stream() + .peek(this::sort) + .forEach(items::add); + } + + if (linkNode == null || element == linkNode) { + items.add(new AddUserDataAction(nodeTree, this)); + } + + if (canRemove()) { + items.add(new RemoveNodeAction(nodeTree, this)); + } + + NodeUtils.children(element) + .flatMap(ControlUtils::controls) + .filter(ControlUtils::isNotEnabled) + .findAny() + .ifPresent(control -> items.add(new EnableAllControlsAction(nodeTree, this))); + + NodeUtils.children(element) + .flatMap(ControlUtils::controls) + .filter(ControlUtils::isEnabled) + .findAny() + .ifPresent(control -> items.add(new DisableAllControlsAction(nodeTree, this))); + + super.fillContextMenu(nodeTree, items); + } + + /** + * Sort items of the menu. + * + * @param menu the menu. + */ + @FxThread + protected void sort(@NotNull Menu menu) { + menu.getItems().sort(ACTION_COMPARATOR); + } + + @Override + @FxThread + public boolean canMove() { + return true; + } + + @Override + @FxThread + public boolean canCopy() { + return true; + } + + @Override + @FxThread + public boolean canAccept(@NotNull TreeNode treeNode, boolean isCopy) { + var element = treeNode.getElement(); + return element instanceof AbstractControl || super.canAccept(treeNode, isCopy); + } + + @Override + @FxThread + public void accept(@NotNull ChangeConsumer changeConsumer, @NotNull Object object, boolean isCopy) { + + var spatial = getElement(); + + if (object instanceof AbstractControl) { + + var control = (AbstractControl) object; + var prevParent = control.getSpatial(); + + if (isCopy) { + var clone = (AbstractControl) control.jmeClone(); + clone.setSpatial(null); + changeConsumer.execute(new AddControlOperation(clone, spatial)); + } else { + changeConsumer.execute(new MoveControlOperation(control, prevParent, spatial)); + } + } + + super.accept(changeConsumer, object, isCopy); + } + + @Override + @FxThread + public boolean canRemove() { + var parent = getElement().getParent(); + return parent != null && parent.getUserData(AbstractSceneEditor3dPart.KEY_MODEL_NODE) != Boolean.TRUE; + } + + /** + * Create creation menu menu. + * + * @param nodeTree the node tree + * @return the menu + */ + @FxThread + protected @NotNull Optional createCreationMenu(@NotNull NodeTree nodeTree) { + + var element = getElement(); + + var menu = new Menu(Messages.MODEL_NODE_TREE_ACTION_CREATE, new ImageView(Icons.ADD_12)); + var createControlMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL, new ImageView(Icons.ADD_12)); + + var createControlItems = createControlMenu.getItems(); + createControlItems.add(new CreateCustomControlAction(nodeTree, this)); + + if (element.getControl(RigidBodyControl.class) == null) { + createControlItems.add(new CreateStaticRigidBodyControlAction(nodeTree, this)); + createControlItems.add(new CreateRigidBodyControlAction(nodeTree, this)); + } + + if (element.getControl(VehicleControl.class) == null) { + createControlItems.add(new CreateVehicleControlAction(nodeTree, this)); + } + + if (element.getControl(CharacterControl.class) == null) { + createControlItems.add(new CreateCharacterControlAction(nodeTree, this)); + } + + if (element.getControl(MotionEvent.class) == null) { + createControlItems.add(new CreateMotionControlAction(nodeTree, this)); + } + + createControlItems.add(new CreateLightControlAction(nodeTree, this)); + + for (var factory : CREATION_CONTROL_ACTION_FACTORIES) { + var menuItem = factory.create(this, nodeTree); + if (menuItem != null) { + createControlItems.add(menuItem); + } + } + + createControlItems.sort(ACTION_COMPARATOR); + + //final SkeletonControl skeletonControl = element.getControl(SkeletonControl.class); + //if (skeletonControl != null) { + //FIXME resultItems.add(new CreateKinematicRagdollControlAction(nodeTree, this)); + //} + + var resultItems = menu.getItems(); + resultItems.add(createControlMenu); + + for (var factory : CREATION_ACTION_FACTORIES) { + var menuItem = factory.create(this, nodeTree); + if (menuItem != null) { + resultItems.add(menuItem); + } + } + + return Optional.of(menu); + } + + /** + * Create tool menu menu. + * + * @param nodeTree the node tree + * @return the menu + */ + @FxThread + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final String name = getElement().getName(); + return name == null ? "name is null" : name; + } + + @Override + @FxThread + public boolean canEditName() { + return true; + } + + @Override + @FxThread + public boolean hasChildren(@NotNull NodeTree nodeTree) { + return nodeTree instanceof ModelNodeTree; + } + + @Override + @FxThread + public void changeName(@NotNull NodeTree nodeTree, @NotNull String newName) { + + if (StringUtils.equals(getName(), newName)){ + return; + } + + super.changeName(nodeTree, newName); + + var spatial = getElement(); + + notNull(nodeTree.getChangeConsumer()) + .execute(new RenameNodeOperation(spatial.getName(), newName, spatial)); + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var result = ArrayFactory.>newArray(TreeNode.class); + var element = getElement(); + + var lightList = element.getLocalLightList(); + lightList.forEach(light -> { + if (!(light instanceof InvisibleObject)) { + result.add(FACTORY_REGISTRY.createFor(light)); + } + }); + + var numControls = element.getNumControls(); + + for (int i = 0; i < numControls; i++) { + result.add(FACTORY_REGISTRY.createFor(element.getControl(i))); + } + + return result; + } + + @Override + @FxThread + public void add(@NotNull TreeNode child) { + super.add(child); + + var element = getElement(); + + if (child instanceof LightTreeNode) { + element.addLight((Light) child.getElement()); + } else if (child instanceof ControlTreeNode) { + element.addControl((Control) child.getElement()); + } + } + + @Override + @FxThread + public void remove(@NotNull TreeNode child) { + super.remove(child); + + var element = getElement(); + + if (child instanceof LightTreeNode) { + element.removeLight((Light) child.getElement()); + } else if (child instanceof ControlTreeNode) { + element.removeControl((Control) child.getElement()); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java new file mode 100644 index 00000000..8b94904e --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java @@ -0,0 +1,119 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.jme3.effect.shapes.EmitterShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateDefaultParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateEmptyParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateRadialParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape.*; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.spatial.GeometryTreeNode; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateDefaultParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateEmptyParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.influencer.CreateRadialParticleInfluencerAction; +import com.ss.builder.fx.control.tree.action.impl.particle.emitter.shape.*; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.collections.ObservableList; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link NodeTreeNode} to represent the {@link ParticleEmitter} in the editor. + * + * @author JavaSaBr + */ +public class ParticleEmitterTreeNode extends GeometryTreeNode { + + public ParticleEmitterTreeNode(@NotNull ParticleEmitter element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.PARTICLES_16; + } + + @Override + @FxThread + public @NotNull Array> getChildren(@NotNull NodeTree nodeTree) { + + var element = getElement(); + var influencerTreeNode = FACTORY_REGISTRY.createFor(element.getParticleInfluencer()); + var shapeTreeNode = FACTORY_REGISTRY.createFor(element.getShape()); + + var children = ArrayFactory.>newArray(TreeNode.class); + + if (influencerTreeNode != null) { + children.add(influencerTreeNode); + } + + if (shapeTreeNode != null) { + children.add(shapeTreeNode); + } + + children.addAll(super.getChildren(nodeTree)); + + return children; + } + + @Override + @FxThread + public void fillContextMenu(@NotNull NodeTree nodeTree, @NotNull ObservableList items) { + + final Menu changeShapeMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_CHANGE_SHAPE, + new ImageView(Icons.EDIT_16)); + + changeShapeMenu.getItems() + .addAll(new CreateBoxShapeEmitterAction(nodeTree, this), + new CreateSphereShapeEmitterAction(nodeTree, this), + new CreatePointShapeEmitterAction(nodeTree, this), + new CreateMeshVertexShapeEmitterAction(nodeTree, this), + new CreateMeshFaceShapeEmitterAction(nodeTree, this), + new CreateMeshConvexHullShapeEmitterAction(nodeTree, this)); + + final Menu changeInfluencerMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_CHANGE_INFLUENCER, + new ImageView(Icons.EDIT_16)); + + changeInfluencerMenu.getItems() + .addAll(new CreateEmptyParticleInfluencerAction(nodeTree, this), + new CreateDefaultParticleInfluencerAction(nodeTree, this), + new CreateRadialParticleInfluencerAction(nodeTree, this)); + + items.add(new ResetParticleEmittersAction(nodeTree, this)); + items.add(changeShapeMenu); + items.add(changeInfluencerMenu); + + super.fillContextMenu(nodeTree, items); + } + + @Override + @FxThread + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } + + @Override + @FxThread + protected @NotNull Optional createCreationMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java new file mode 100644 index 00000000..689e4748 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer; + +import com.jme3.effect.influencers.DefaultParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link DefaultParticleInfluencer} in the editor. + * + * @author JavaSaBr + */ +public class DefaultParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { + + public DefaultParticleInfluencerTreeNode(@NotNull final DefaultParticleInfluencer element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_DEFAULT; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java new file mode 100644 index 00000000..629f292c --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer; + +import com.jme3.effect.influencers.EmptyParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link EmptyParticleInfluencer} in the editor. + * + * @author JavaSaBr + */ +public class EmptyParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { + + public EmptyParticleInfluencerTreeNode(@NotNull final EmptyParticleInfluencer element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_EMPTY; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java new file mode 100644 index 00000000..06d6b554 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer; + +import com.jme3.effect.influencers.ParticleInfluencer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link TreeNode} for representing the {@link ParticleInfluencer} in the editor. + * + * @author JavaSaBr + */ +public class ParticleInfluencerTreeNode extends TreeNode { + + public ParticleInfluencerTreeNode(@NotNull final ParticleInfluencer element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.INFLUENCER_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final ParticleInfluencer element = getElement(); + return element.getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java new file mode 100644 index 00000000..b8873fdd --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.influencer; + +import com.jme3.effect.influencers.RadialParticleInfluencer; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link RadialParticleInfluencer} in the editor. + * + * @author JavaSaBr + */ +public class RadialParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { + + public RadialParticleInfluencerTreeNode(@NotNull final RadialParticleInfluencer element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_RADIAL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java new file mode 100644 index 00000000..f0ebd9a5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterBoxShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterShapeTreeNode} in the editor. + * + * @author JavaSaBr + */ +public class EmitterBoxShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterBoxShapeTreeNode(@NotNull final EmitterBoxShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.CUBE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_BOX; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java new file mode 100644 index 00000000..fdc65914 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterMeshConvexHullShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshConvexHullShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterMeshConvexHullShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterMeshConvexHullShapeTreeNode(@NotNull final EmitterMeshConvexHullShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_CONVEX_HULL; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java new file mode 100644 index 00000000..1dc8a6bd --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterMeshFaceShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshFaceShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterMeshFaceShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterMeshFaceShapeTreeNode(@NotNull final EmitterMeshFaceShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_FACE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java new file mode 100644 index 00000000..3cd5b59d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterMeshVertexShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshVertexShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterMeshVertexShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterMeshVertexShapeTreeNode(@NotNull final EmitterMeshVertexShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_VERTEX; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java new file mode 100644 index 00000000..c074f659 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterPointShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterPointShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterPointShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterPointShapeTreeNode(@NotNull final EmitterPointShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.POINTS_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_POINT; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java new file mode 100644 index 00000000..d3714a7d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterShape; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link TreeNode} for representing the {@link EmitterShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterShapeTreeNode extends TreeNode { + + public EmitterShapeTreeNode(@NotNull final EmitterShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.GEOMETRY_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + final EmitterShape element = getElement(); + return element.getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java new file mode 100644 index 00000000..1ee981d4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java @@ -0,0 +1,38 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.particle.emitter.shape; + +import com.jme3.effect.shapes.EmitterSphereShape; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterSphereShape} in the editor. + * + * @author JavaSaBr + */ +public class EmitterSphereShapeTreeNode extends EmitterShapeTreeNode { + + public EmitterSphereShapeTreeNode(@NotNull final EmitterSphereShape element, final long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.SPHERE_16; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_SPHERE; + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java new file mode 100644 index 00000000..7c7e5195 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java @@ -0,0 +1,46 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.terrain; + +import com.jme3.terrain.geomipmap.TerrainGrid; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.control.Menu; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link TreeNode} to represent a {@link TerrainGrid} in an editor. + * + * @author JavaSaBr + */ +public class TerrainGridTreeNode extends NodeTreeNode { + + public TerrainGridTreeNode(@NotNull TerrainGrid element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.TERRAIN_16; + } + + @Override + @FxThread + protected @NotNull Optional createCreationMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } + + @Override + @FxThread + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } +} diff --git a/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java new file mode 100644 index 00000000..ae47dc11 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java @@ -0,0 +1,40 @@ +package com.ss.builder.fx.control.tree.node.impl.spatial.terrain; + +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.tree.node.impl.spatial.NodeTreeNode; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import javafx.scene.control.Menu; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of the {@link TreeNode} to represent a {@link TerrainQuad} in an editor. + * + * @author JavaSaBr + */ +public class TerrainQuadTreeNode extends NodeTreeNode { + + public TerrainQuadTreeNode(@NotNull TerrainQuad element, long objectId) { + super(element, objectId); + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.TERRAIN_16; + } + + @Override + @FxThread + protected @NotNull Optional createToolMenu(@NotNull NodeTree nodeTree) { + return Optional.empty(); + } +} diff --git a/src/main/java/com/ss/editor/ui/css/CssClasses.java b/src/main/java/com/ss/builder/fx/css/CssClasses.java similarity index 99% rename from src/main/java/com/ss/editor/ui/css/CssClasses.java rename to src/main/java/com/ss/builder/fx/css/CssClasses.java index 89a65657..2c69803f 100644 --- a/src/main/java/com/ss/editor/ui/css/CssClasses.java +++ b/src/main/java/com/ss/builder/fx/css/CssClasses.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.css; +package com.ss.builder.fx.css; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/css/CssColorTheme.java b/src/main/java/com/ss/builder/fx/css/CssColorTheme.java new file mode 100644 index 00000000..c6aeeba4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/css/CssColorTheme.java @@ -0,0 +1,115 @@ +package com.ss.builder.fx.css; + +import com.ss.builder.annotation.FromAnyThread; +import javafx.scene.paint.Color; +import org.jetbrains.annotations.NotNull; + +/** + * The list of color themes. + * + * @author JavaSaBr + */ +public enum CssColorTheme { + LIGHT("/ui/css/light-color.css", "White", Color.web("#5d626e"), Color.web("#ffffff")), + SHADOW("/ui/css/shadow-color.css", "Shadow", Color.web("#c8d2e1"), Color.web("#404552")), + DARK("/ui/css/dark-color.css", "Dark", Color.web("#c8dae2"), Color.web("#3c3f41")),; + + @NotNull + public static final CssColorTheme[] VALUES = values(); + + @NotNull + public static CssColorTheme valueOf(final int index) { + return VALUES[index]; + } + + /** + * The icon color. + */ + @NotNull + private final Color iconColor; + + /** + * The background color. + */ + @NotNull + private final Color backgroundColor; + + /** + * The css file. + */ + @NotNull + private final String cssFile; + + /** + * The name of this theme. + */ + @NotNull + private final String name; + + CssColorTheme( + @NotNull String cssFile, + @NotNull String name, + @NotNull Color iconColor, + @NotNull Color backgroundColor + ) { + this.cssFile = cssFile; + this.name = name; + this.iconColor = iconColor; + this.backgroundColor = backgroundColor; + } + + /** + * Get the name of this theme. + * + * @return the name of this theme. + */ + @FromAnyThread + public @NotNull String getName() { + return name; + } + + /** + * Get the css file. + * + * @return the css file. + */ + @FromAnyThread + public @NotNull String getCssFile() { + return cssFile; + } + + /** + * Get the icon color. + * + * @return the icon color. + */ + @FromAnyThread + public @NotNull Color getIconColor() { + return iconColor; + } + + /** + * Get the background color. + * + * @return the background color. + */ + @FromAnyThread + public @NotNull Color getBackgroundColor() { + return backgroundColor; + } + + /** + * Return true if this theme is dark. + * + * @return true if this theme is dark. + */ + @FromAnyThread + public boolean needRepaintIcons() { + return true; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/com/ss/editor/ui/css/CssIds.java b/src/main/java/com/ss/builder/fx/css/CssIds.java similarity index 96% rename from src/main/java/com/ss/editor/ui/css/CssIds.java rename to src/main/java/com/ss/builder/fx/css/CssIds.java index 0198e898..410768e6 100644 --- a/src/main/java/com/ss/editor/ui/css/CssIds.java +++ b/src/main/java/com/ss/builder/fx/css/CssIds.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.css; +package com.ss.builder.fx.css; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/css/CssRegistry.java b/src/main/java/com/ss/builder/fx/css/CssRegistry.java new file mode 100644 index 00000000..f376d5a2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/css/CssRegistry.java @@ -0,0 +1,156 @@ +package com.ss.builder.fx.css; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.fx.event.impl.CssAppliedEvent; +import com.ss.builder.fx.event.impl.FxSceneCreatedEvent; +import com.ss.builder.fx.event.impl.PluginCssLoadedEvent; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.AsyncEventManager; +import com.ss.builder.manager.AsyncEventManager.CombinedAsyncEventHandlerBuilder; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.builder.EditorFxSceneBuilder; +import com.ss.builder.fx.event.impl.CssAppliedEvent; +import com.ss.builder.fx.event.impl.FxSceneCreatedEvent; +import com.ss.builder.fx.event.impl.PluginCssLoadedEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +import java.net.URL; + +/** + * The registry of available css files. + * + * @author JavaSaBr + */ +public class CssRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(CssRegistry.class); + + /** + * The path to the base CSS styles. + */ + public static final String CSS_FILE_BASE = "ui/css/base.css"; + + /** + * The path to the external CSS styles. + */ + public static final String CSS_FILE_EXTERNAL = "ui/css/external.css"; + + /** + * The path to the custom ids CSS styles. + */ + public static final String CSS_FILE_CUSTOM_IDS = "ui/css/custom_ids.css"; + + /** + * The path to the custom classes CSS styles. + */ + public static final String CSS_FILE_CUSTOM_CLASSES = "ui/css/custom_classes.css"; + + private static final CssRegistry INSTANCE = new CssRegistry(); + + @FromAnyThread + public static @NotNull CssRegistry getInstance() { + return INSTANCE; + } + + /** + * The list of available css files. + */ + @NotNull + private final Array availableCssFiles; + + private CssRegistry() { + InitializeManager.valid(getClass()); + + this.availableCssFiles = ArrayFactory.newCopyOnModifyArray(String.class); + + var classLoader = EditorFxSceneBuilder.class.getClassLoader(); + + register(CSS_FILE_BASE, classLoader); + register(CSS_FILE_EXTERNAL, classLoader); + register(CSS_FILE_CUSTOM_IDS, classLoader); + register(CSS_FILE_CUSTOM_CLASSES, classLoader); + + // if a scene was created before when we loaded plugin's css. + CombinedAsyncEventHandlerBuilder.of(this::applyCssToScene) + .add(FxSceneCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + + CombinedAsyncEventHandlerBuilder.of(this::applyCssToScene) + .add(PluginCssLoadedEvent.EVENT_TYPE) + .add(FxSceneCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + + LOGGER.info("initialized."); + } + + /** + * Apply all loaded CSS files to the main scene. + */ + @BackgroundThread + private void applyCssToScene() { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + + var editorConfig = EditorConfig.getInstance(); + var theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); + + var scene = EditorUtils.getFxScene(); + var stylesheets = scene.getStylesheets(); + + // check if we have nothing new + if (stylesheets.size() == getAvailableCssFiles().size() + 1) { + return; + } + + stylesheets.clear(); + stylesheets.addAll(getAvailableCssFiles()); + stylesheets.add(theme.getCssFile()); + + AsyncEventManager.getInstance() + .notify(new CssAppliedEvent()); + + LOGGER.info("applied CSS to the main scene."); + }); + } + + /** + * Add the CSS file to this registry. + * + * @param cssFile the URL to the CSS file. + */ + @FromAnyThread + public void register(@NotNull URL cssFile) { + availableCssFiles.add(cssFile.toExternalForm()); + } + + /** + * Add the CSS file to this registry. + * + * @param cssFile the path to CSS file. + * @param classLoader the class loader which can load this path. + */ + @FromAnyThread + public void register(@NotNull String cssFile, @NotNull ClassLoader classLoader) { + register(notNull(classLoader.getResource(cssFile))); + } + + /** + * Get a list of available CSS files. + * + * @return the list of available css files. + */ + @FromAnyThread + public @NotNull Array getAvailableCssFiles() { + return availableCssFiles; + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/AbstractSimpleEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/AbstractSimpleEditorDialog.java new file mode 100644 index 00000000..45fc6191 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/AbstractSimpleEditorDialog.java @@ -0,0 +1,201 @@ +package com.ss.builder.fx.dialog; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The simple implementation of the dialog. + * + * @author JavaSaBr + */ +public abstract class AbstractSimpleEditorDialog extends EditorDialog { + + public static final double DEFAULT_LABEL_W_PERCENT = 0.4; + public static final double DEFAULT_FIELD_W_PERCENT = 0.6; + + public static final double DEFAULT_LABEL_W_PERCENT2 = 0.5; + public static final double DEFAULT_FIELD_W_PERCENT2 = 0.5; + + public static final double DEFAULT_LABEL_W_PERCENT3 = 0.6; + public static final double DEFAULT_FIELD_W_PERCENT3 = 0.4; + + public static final double DEFAULT_FIELD_W_PERCENT4 = 0.3; + + /** + * The ok button. + */ + @Nullable + private Button okButton; + + /** + * The close button. + */ + @Nullable + private Button closeButton; + + @Override + @FxThread + protected void processKey(@NotNull KeyEvent event) { + super.processKey(event); + var okButton = getOkButton(); + if (okButton != null && event.getCode() == KeyCode.ENTER && !okButton.isDisable()) { + processOk(); + } + } + + @Override + @FxThread + protected void createContent(@NotNull GridPane root) { + super.createContent(root); + } + + /** + * Get the ok button. + * + * @return the ok button. + */ + @FxThread + protected @Nullable Button getOkButton() { + return okButton; + } + + /** + * Get the close button. + * + * @return the close button. + */ + @FxThread + protected @Nullable Button getCloseButton() { + return closeButton; + } + + @Override + @FxThread + protected void createActions(@NotNull VBox root) { + super.createActions(root); + + var container = new HBox(); + + createBeforeActions(container); + + if (needOkButton()) { + + okButton = new Button(getButtonOkText()); + okButton.setOnAction(event -> safeProcessOk()); + + FxUtils.addClass(okButton, + CssClasses.DIALOG_BUTTON); + } + + if (needCloseButton()) { + + closeButton = new Button(getButtonCloseText()); + closeButton.setOnAction(event -> processClose()); + + FxUtils.addClass(closeButton, + CssClasses.DIALOG_BUTTON); + } + + if (needOkButton()) { + FxUtils.addChild(container, okButton); + } + + if (needCloseButton()) { + FxUtils.addChild(container, closeButton); + } + + createAdditionalActions(container); + + if (!container.getChildren().isEmpty()) { + FxUtils.addClass(container, CssClasses.DEF_HBOX); + FxUtils.addChild(root, container); + } + } + + @FxThread + protected void createBeforeActions(@NotNull HBox container) { + + } + + @FxThread + protected void createAdditionalActions(@NotNull HBox container) { + + } + + /** + * Return true if need to add an ok button here. + * + * @return true if need to add an ok button here. + */ + @FromAnyThread + protected boolean needOkButton() { + return true; + } + + /** + * Return true if need to add a close button here. + * + * @return true if need to add a close button here. + */ + @FromAnyThread + protected boolean needCloseButton() { + return true; + } + + @FxThread + private void safeProcessOk() { + try { + processOk(); + } catch (Exception e) { + EditorUtils.handleException(LOGGER, this, e); + } + } + + /** + * Get the button's close text. + * + * @return the the button's close text. + */ + @FromAnyThread + protected @NotNull String getButtonCloseText() { + return Messages.SIMPLE_DIALOG_BUTTON_CLOSE; + } + + /** + * Get button's ok text. + * + * @return the button's ok text. + */ + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_OK; + } + + /** + * Handle ok button. + */ + @FxThread + protected void processOk() { + hide(); + } + + /** + * Handle cancel button. + */ + @FxThread + protected void processClose() { + hide(); + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/ConfirmDialog.java b/src/main/java/com/ss/builder/fx/dialog/ConfirmDialog.java new file mode 100644 index 00000000..12cfc02a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/ConfirmDialog.java @@ -0,0 +1,138 @@ +package com.ss.builder.fx.dialog; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.function.Consumer; + +/** + * The implementation of a dialog to ask questions. + * + * @author JavaSaBr + */ +public class ConfirmDialog extends AbstractSimpleEditorDialog { + + @NotNull + private static final Point DIALOG_SIZE = new Point(600, -1); + + @FxThread + public static void ifOk(@NotNull String question, @NotNull Runnable handler) { + + var dialog = new ConfirmDialog(aBoolean -> { + + if (Boolean.TRUE.equals(aBoolean)) { + handler.run(); + } + + }, question); + + dialog.postConstruct(); + dialog.show(); + } + + /** + * The handler of an answer. + */ + @NotNull + private final Consumer handler; + + /** + * The label. + */ + @NotNull + private final Label questionLabel; + + public ConfirmDialog(@NotNull Consumer handler, @NotNull String question) { + this.handler = handler; + this.questionLabel = new Label(question); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.QUESTION_DIALOG_TITLE; + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + super.createContent(root); + + questionLabel.minWidthProperty() + .bind(widthProperty().multiply(0.9)); + + FxUtils.addClass(root, CssClasses.CONFIRM_DIALOG); + FxUtils.addChild(root, questionLabel); + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_YES; + } + + @Override + @FromAnyThread + protected @NotNull String getButtonCloseText() { + return Messages.SIMPLE_DIALOG_BUTTON_NO; + } + + @Override + @FxThread + protected void processKey(@NotNull KeyEvent event) { + if (event.getCode() == KeyCode.ENTER) { + processClose(); + } + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + handler.accept(Boolean.TRUE); + } + + @Override + @FxThread + protected void processClose() { + super.processClose(); + handler.accept(Boolean.FALSE); + } + + /** + * Process cancel the dialog. + */ + protected void processCancel() { + super.processClose(); + handler.accept(null); + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } + + @Override + @FxThread + protected void createAdditionalActions(@NotNull HBox container) { + super.createAdditionalActions(container); + + var closeButton = new Button(Messages.SIMPLE_DIALOG_BUTTON_CANCEL); + closeButton.setOnAction(event -> processCancel()); + + FxUtils.addClass(closeButton, CssClasses.DIALOG_BUTTON); + FxUtils.addChild(container, closeButton); + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java b/src/main/java/com/ss/builder/fx/dialog/CreateCustomControlDialog.java similarity index 94% rename from src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java rename to src/main/java/com/ss/builder/fx/dialog/CreateCustomControlDialog.java index 5e993f7b..11b32a2b 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/CreateCustomControlDialog.java @@ -1,19 +1,19 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.dictionary.DictionaryFactory.newObjectDictionary; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.control.EditableControl; import com.ss.editor.extension.scene.control.impl.EditableBillboardControl; -import com.ss.editor.manager.ClasspathManager; -import com.ss.editor.manager.ClasspathManager.Scope; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddControlOperation; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ClasspathManager.Scope; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddControlOperation; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.ClassUtils; import com.ss.rlib.common.util.StringUtils; diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java b/src/main/java/com/ss/builder/fx/dialog/CreateSceneAppStateDialog.java similarity index 95% rename from src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java rename to src/main/java/com/ss/builder/fx/dialog/CreateSceneAppStateDialog.java index a9085bcb..fbd4545e 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/CreateSceneAppStateDialog.java @@ -1,20 +1,20 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; -import static com.ss.editor.util.EditorUtil.tryToCreateUserObject; +import static com.ss.builder.util.EditorUtils.tryToCreateUserObject; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.dictionary.DictionaryFactory.newObjectDictionary; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.EditableSceneAppState; import com.ss.editor.extension.scene.app.state.SceneAppState; import com.ss.editor.extension.scene.app.state.impl.bullet.EditableBulletSceneAppState; import com.ss.editor.extension.scene.app.state.impl.pbr.StaticLightProbeSceneAppState; import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.model.undo.impl.AddAppStateOperation; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.AddAppStateOperation; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.ClassUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java b/src/main/java/com/ss/builder/fx/dialog/CreateSceneFilterDialog.java similarity index 95% rename from src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java rename to src/main/java/com/ss/builder/fx/dialog/CreateSceneFilterDialog.java index c05b0d26..23c93d80 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/CreateSceneFilterDialog.java @@ -1,19 +1,19 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; -import static com.ss.editor.util.EditorUtil.tryToCreateUserObject; +import static com.ss.builder.util.EditorUtils.tryToCreateUserObject; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.dictionary.DictionaryFactory.newObjectDictionary; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.SceneAppState; import com.ss.editor.extension.scene.filter.EditableSceneFilter; import com.ss.editor.extension.scene.filter.SceneFilter; import com.ss.editor.extension.scene.filter.impl.*; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.model.undo.impl.AddSceneFilterOperation; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.model.undo.impl.AddSceneFilterOperation; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.ClassUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/EditorDialog.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/EditorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/EditorDialog.java index a7f19009..0038d99f 100644 --- a/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/EditorDialog.java @@ -1,19 +1,14 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; import static javafx.geometry.Pos.CENTER; -import com.ss.editor.JmeApplication; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.css.CssRegistry; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.scene.EditorFxScene; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.JmeApplication; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.scene.EditorFxScene; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.fx.util.FXUtils; @@ -47,9 +42,6 @@ public class EditorDialog { protected static final Logger LOGGER = LoggerManager.getLogger(EditorDialog.class); - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - protected static final CssRegistry CSS_REGISTRY = CssRegistry.getInstance(); - /** * The default dialog size. */ @@ -62,7 +54,7 @@ public class EditorDialog { private final Stage dialog; /** - * The time when this DIALOG was showed. + * The time when this dialog was showed. */ @NotNull private volatile LocalTime showedTime; @@ -79,21 +71,23 @@ public class EditorDialog { @Nullable private Node focusOwner; + /** + * The flat about that this dialog was full constructed. + */ + private volatile boolean ready; + public EditorDialog() { this.showedTime = LocalTime.now(); container = new VBox(); container.setAlignment(CENTER); - var editorConfig = EditorConfig.getInstance(); - var theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); - + var mainScene = EditorUtils.getFxScene(); var scene = new Scene(container); - var stylesheets = scene.getStylesheets(); - stylesheets.addAll(CSS_REGISTRY.getAvailableCssFiles()); - stylesheets.add(theme.getCssFile()); + scene.getStylesheets() + .addAll(mainScene.getStylesheets()); - createControls(container); + var fxStage = EditorUtils.getFxStage(); dialog = new Stage(); dialog.setTitle(getTitleText()); @@ -101,12 +95,24 @@ public EditorDialog() { dialog.initModality(Modality.WINDOW_MODAL); dialog.setResizable(isResizable()); dialog.setScene(scene); + dialog.getIcons() + .addAll(fxStage.getIcons()); + } + + /** + * Construct content of this dialog after constructor. + */ + @FxThread + public void postConstruct() { - var fxStage = EditorUtil.getFxStage(); - var icons = dialog.getIcons(); - icons.addAll(fxStage.getIcons()); + if (ready) { + return; + } + createControls(container); configureSize(container); + + ready = true; } /** @@ -130,14 +136,25 @@ protected void createControls(@NotNull VBox root) { var actionsContainer = new VBox(); if (isGridStructure()) { + var container = new GridPane(); - FxUtils.addClass(container, CssClasses.DEF_GRID_PANE, CssClasses.DIALOG_CONTENT_ROOT); + + FxUtils.addClass(container, + CssClasses.DEF_GRID_PANE, CssClasses.DIALOG_CONTENT_ROOT); + createContent(container); + FxUtils.addChild(root, container); + } else { + var container = new VBox(); - FxUtils.addClass(container, CssClasses.DEF_VBOX, CssClasses.DIALOG_CONTENT_ROOT); + + FxUtils.addClass(container, + CssClasses.DEF_VBOX, CssClasses.DIALOG_CONTENT_ROOT); + createContent(container); + FxUtils.addChild(root, container); } @@ -281,7 +298,7 @@ public void show(@NotNull Node owner) { */ @FxThread public void show() { - show(EditorUtil.getFxLastWindow()); + show(EditorUtils.getFxLastWindow()); } /** @@ -291,6 +308,7 @@ public void show() { */ @FxThread public void show(@NotNull Window owner) { + postConstruct(); var scene = owner.getScene(); @@ -300,7 +318,7 @@ public void show(@NotNull Window owner) { container.setFocusTraversable(false); } - focusOwner = scene.getFocusOwner(); + focusOwner = scene == null ? null : scene.getFocusOwner(); dialog.initOwner(owner); dialog.show(); @@ -311,7 +329,7 @@ public void show(@NotNull Window owner) { GAnalytics.sendPageView(getDialogId(), null, "/dialog/" + getDialogId()); GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_OPENED, getDialogId()); - EditorUtil.addFxWindow(dialog); + EditorUtils.addFxWindow(dialog); Platform.runLater(dialog::sizeToScene); } @@ -347,7 +365,7 @@ public void hide() { dialog.hide(); - EditorUtil.removeFxWindow(window); + EditorUtils.removeFxWindow(window); GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_CLOSED, getDialogId()); GAnalytics.sendTiming(GAEvent.Category.DIALOG, GAEvent.Label.SHOWING_A_DIALOG, seconds, getDialogId()); diff --git a/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java b/src/main/java/com/ss/builder/fx/dialog/GenerateTangentsDialog.java similarity index 92% rename from src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java rename to src/main/java/com/ss/builder/fx/dialog/GenerateTangentsDialog.java index 08b67ffc..05ab9bc3 100644 --- a/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/GenerateTangentsDialog.java @@ -1,18 +1,18 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static javafx.collections.FXCollections.observableArrayList; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.util.TangentGenerator; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.impl.ChangeMeshOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.TangentGenerator; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.ChangeMeshOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import javafx.collections.ObservableList; import javafx.scene.control.CheckBox; diff --git a/src/main/java/com/ss/builder/fx/dialog/RenameDialog.java b/src/main/java/com/ss/builder/fx/dialog/RenameDialog.java new file mode 100644 index 00000000..6221c7ce --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/RenameDialog.java @@ -0,0 +1,194 @@ +package com.ss.builder.fx.dialog; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * The implementation of a dialog for renaming. + * + * @author JavaSaBr + */ +public class RenameDialog extends AbstractSimpleEditorDialog { + + private static final Point DIALOG_SIZE = new Point(400, 0); + + /** + * The text field. + */ + @NotNull + private final TextField nameField; + + /** + * The function for validation name. + */ + @Nullable + private Function validator; + + /** + * The function for handling a new name. + */ + @Nullable + private Consumer handler; + + public RenameDialog() { + nameField = new TextField(); + } + + @Override + @FxThread + protected void createContent(@NotNull GridPane root) { + super.createContent(root); + + var nameLabel = new Label(Messages.RENAME_DIALOG_NEW_NAME_LABEL + ":"); + nameLabel.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); + + nameField.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onTextChange(nameField, this::validateName); + + root.add(nameLabel, 0, 0); + root.add(nameField, 1, 0); + + FxUtils.addClass(nameLabel, CssClasses.DIALOG_DYNAMIC_LABEL) + .addClass(nameField, CssClasses.DIALOG_FIELD); + } + + @Override + @FromAnyThread + protected boolean isGridStructure() { + return true; + } + + @Override + @FxThread + public void show(@NotNull Window owner) { + super.show(owner); + + ExecutorManager.getInstance() + .addFxTask(() -> getNameField().requestFocus()); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.RENAME_DIALOG_TITLE; + } + + /** + * Set the initial name. + * + * @param initName the initial name. + */ + @FxThread + public void setInitName(@NotNull String initName) { + getNameField().setText(initName); + } + + /** + * Get the text field. + * + * @return the text field. + */ + @FxThread + private @NotNull TextField getNameField() { + return nameField; + } + + /** + * Get the function for validation name. + * + * @return the function for validation name. + */ + @FxThread + private @Nullable Function getValidator() { + return validator; + } + + /** + * Set the function for validation name. + * + * @param validator the function for validation name. + */ + @FxThread + public void setValidator(@Nullable Function validator) { + this.validator = validator; + } + + /** + * Get the function for handling a new name. + * + * @return the function for handling a new name. + */ + @FxThread + private @Nullable Consumer getHandler() { + return handler; + } + + /** + * Set the function for handling a new name. + * + * @param handler the function for handling a new name. + */ + @FxThread + public void setHandler(@Nullable Consumer handler) { + this.handler = handler; + } + + /** + * Validate a new name. + */ + @FxThread + private void validateName(@NotNull String name) { + var validator = getValidator(); + getOkButton().setDisable(!(validator == null || validator.apply(name))); + } + + @Override + @FromAnyThread + protected @NotNull String getButtonCloseText() { + return Messages.SIMPLE_DIALOG_BUTTON_CANCEL; + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.RENAME_DIALOG_BUTTON_OK; + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + + var handler = getHandler(); + + if (handler == null) { + return; + } + + handler.accept(getNameField().getText()); + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java b/src/main/java/com/ss/builder/fx/dialog/SettingsDialog.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java rename to src/main/java/com/ss/builder/fx/dialog/SettingsDialog.java index 2c943fe1..9f97b3ec 100644 --- a/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/SettingsDialog.java @@ -1,33 +1,32 @@ -package com.ss.editor.ui.dialog; +package com.ss.builder.fx.dialog; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.*; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; -import static com.ss.editor.plugin.api.property.control.PropertyEditorControlFactory.build; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.*; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.*; +import static com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory.build; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; -import com.ss.editor.JfxApplication; -import com.ss.editor.JmeApplication; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ClasspathManager; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.part3d.editor.impl.scene.SceneEditor3DPart; -import com.ss.editor.plugin.api.property.control.PropertyEditorControl; -import com.ss.editor.plugin.api.settings.SettingsCategory; -import com.ss.editor.plugin.api.settings.SettingsPropertyDefinition; -import com.ss.editor.plugin.api.settings.SettingsProviderRegistry; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.JfxApplication; +import com.ss.builder.JmeApplication; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.jme.editor.part3d.impl.scene.SceneEditor3dPart; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.plugin.api.settings.SettingsCategory; +import com.ss.builder.plugin.api.settings.SettingsPropertyDefinition; +import com.ss.builder.plugin.api.settings.SettingsProviderRegistry; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.fx.util.FxUtils; import javafx.application.Platform; import javafx.scene.control.Button; @@ -72,7 +71,13 @@ public class SettingsDialog extends EditorDialog { private Label messageLabel; public SettingsDialog() { - FXUtils.addClassTo(getContainer(), CssClasses.SETTINGS_DIALOG); + FxUtils.addClass(getContainer(), CssClasses.SETTINGS_DIALOG); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); validate(); } @@ -182,7 +187,7 @@ private void validate() { controls.forEach(PropertyEditorControl::checkDependency); } - var requiredRestart = controls == null ? null : controls.search(control -> { + var requiredRestart = controls == null ? null : controls.findAny(control -> { var propertyId = control.getPropertyId(); var registry = SettingsProviderRegistry.getInstance(); return registry.isRequiredRestart(propertyId) && control.isNotDefault(); @@ -235,19 +240,19 @@ private void processOk() { editorConfig.save(); - var requiredRestart = controls.search(control -> { + var requiredRestart = controls.findAny(control -> { var propertyId = control.getPropertyId(); var registry = SettingsProviderRegistry.getInstance(); return registry.isRequiredRestart(propertyId) && control.isNotDefault(); }); - var requiredUpdateClasspath = controls.search(control -> { + var requiredUpdateClasspath = controls.findAny(control -> { var propertyId = control.getPropertyId(); var registry = SettingsProviderRegistry.getInstance(); return registry.isRequiredUpdateClasspath(propertyId) && control.isNotDefault(); }); - var reshape3DView = controls.search(control -> { + var reshape3DView = controls.findAny(control -> { var propertyId = control.getPropertyId(); var registry = SettingsProviderRegistry.getInstance(); return registry.isRequiredReshape3DView(propertyId) && control.isNotDefault(); @@ -263,7 +268,7 @@ private void processOk() { var jmeApplication = JmeApplication.getInstance(); var sceneEditor3DPart = jmeApplication.getStateManager() - .getState(SceneEditor3DPart.class); + .getState(SceneEditor3dPart.class); var filter = jmeApplication.getToneMapFilter(); filter.setWhitePoint(editorConfig.getVector3f(PREF_FILTER_TONEMAP_WHITE_POINT, @@ -284,7 +289,7 @@ private void processOk() { var classpathManager = ClasspathManager.getInstance(); classpathManager.reload(); - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); assetManager.clearCache(); } diff --git a/src/main/java/com/ss/builder/fx/dialog/about/AboutDialog.java b/src/main/java/com/ss/builder/fx/dialog/about/AboutDialog.java new file mode 100644 index 00000000..5e1ac9c3 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/about/AboutDialog.java @@ -0,0 +1,137 @@ +package com.ss.builder.fx.dialog.about; + +import com.ss.builder.JfxApplication; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.Config; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.image.ImageView; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; + +/** + * The dialog about this editor. + * + * @author JavaSaBr + */ +public class AboutDialog extends AbstractSimpleEditorDialog { + + private static final String PROJECT_HOME = + "https://bitbucket.org/JavaSabr/jmonkeybuilder"; + + private static final String FORUM_THREAD = + "https://hub.jmonkeyengine.org/t/editor-jmonkeybuilder"; + + private static final Point DIALOG_SIZE = new Point(600, -1); + + private static final String ICONS = + FileUtils.readFromClasspath("/credits/icons.txt"); + + private static final String LIBRARIES = + FileUtils.readFromClasspath("/credits/libraries.txt"); + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + super.createContent(root); + + var application = JfxApplication.getInstance(); + var hostServices = application.getHostServices(); + + var gridPane = new GridPane(); + + var applicationLabel = new Label(Config.TITLE, new ImageView(Icons.APPLICATION_64)); + + var versionLabel = new Label(Messages.ABOUT_DIALOG_VERSION + ":"); + versionLabel.prefWidthProperty() + .bind(gridPane.widthProperty().multiply(0.5)); + + var versionField = new Label(Config.STRING_VERSION); + + var projectHomeLabel = new Label(Messages.ABOUT_DIALOG_PROJECT_HOME + ":"); + + var projectHomeField = new Hyperlink("bitbucket.org"); + projectHomeField.setOnAction(event -> hostServices.showDocument(PROJECT_HOME)); + projectHomeField.setFocusTraversable(false); + + var forumThreadLabel = new Label(Messages.ABOUT_DIALOG_FORUM_THREAD + ":"); + + var forumThreadField = new Hyperlink("hub.jmonkeyengine.org"); + forumThreadField.setOnAction(event -> hostServices.showDocument(FORUM_THREAD)); + forumThreadField.setFocusTraversable(false); + + var usedLibrariesLabel = new Label(Messages.ABOUT_DIALOG_USED_LIBRARIES + ":"); + usedLibrariesLabel.prefWidthProperty() + .bind(gridPane.widthProperty()); + + var usedIcons = new Label(Messages.ABOUT_DIALOG_USED_ICONS + ":"); + usedIcons.prefWidthProperty() + .bind(gridPane.widthProperty()); + + var librariesArea = new TextArea(LIBRARIES); + librariesArea.setEditable(false); + librariesArea.setFocusTraversable(false); + + var iconsArea = new TextArea(ICONS); + iconsArea.setEditable(false); + iconsArea.setFocusTraversable(false); + + gridPane.add(applicationLabel, 0, 0, 2, 1); + gridPane.add(versionLabel, 0, 1, 1, 1); + gridPane.add(versionField, 1, 1, 1, 1); + gridPane.add(projectHomeLabel, 0, 2, 1, 1); + gridPane.add(projectHomeField, 1, 2, 1, 1); + gridPane.add(forumThreadLabel, 0, 3, 1, 1); + gridPane.add(forumThreadField, 1, 3, 1, 1); + gridPane.add(usedLibrariesLabel, 0, 4, 2, 1); + gridPane.add(librariesArea, 0, 5, 2, 1); + gridPane.add(usedIcons, 0, 6, 2, 1); + gridPane.add(iconsArea, 0, 7, 2, 1); + + FxUtils.addClass(root, + CssClasses.ABOUT_DIALOG) + .addClass(gridPane, + CssClasses.DEF_GRID_PANE) + .addClass(usedLibrariesLabel, usedIcons, + CssClasses.ABOUT_DIALOG_LONG_LABEL) + .addClass(versionLabel, projectHomeLabel, forumThreadLabel, + CssClasses.SPECIAL_FONT_16) + .addClass(usedLibrariesLabel, usedIcons, versionField, + CssClasses.SPECIAL_FONT_16) + .addClass(projectHomeField, forumThreadField, + CssClasses.SPECIAL_FONT_16) + .addClass(applicationLabel, + CssClasses.ABOUT_DIALOG_TITLE_LABEL); + + FxUtils.addChild(root, gridPane); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.ABOUT_DIALOG_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_OK; + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java b/src/main/java/com/ss/builder/fx/dialog/animation/ExtractSubAnimationDialog.java similarity index 80% rename from src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java rename to src/main/java/com/ss/builder/fx/dialog/animation/ExtractSubAnimationDialog.java index c50fa195..fa15eee5 100644 --- a/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/animation/ExtractSubAnimationDialog.java @@ -1,22 +1,35 @@ -package com.ss.editor.ui.dialog.animation; +package com.ss.builder.fx.dialog.animation; -import static com.ss.editor.util.AnimationUtils.extractAnimation; +import static com.ss.builder.util.AnimationUtils.extractAnimation; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.model.undo.impl.animation.AddAnimationNodeOperation; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.AnimationUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.animation.AddAnimationNodeOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.AnimationUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.model.undo.impl.animation.AddAnimationNodeOperation; +import com.ss.builder.fx.control.tree.node.impl.control.legacyanim.AnimationTreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.AnimationUtils; import com.ss.rlib.fx.control.input.IntegerTextField; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.control.Label; @@ -215,7 +228,7 @@ private void processExtract() { startFrame = endFrame - 1; } - final Animation subAnimation = extractAnimation(animation, nameField.getText(), startFrame, endFrame); + final Animation subAnimation = AnimationUtils.extractAnimation(animation, nameField.getText(), startFrame, endFrame); final NodeTree nodeTree = getNodeTree(); final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/BaseAssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/BaseAssetEditorDialog.java new file mode 100644 index 00000000..d4ad2db4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/BaseAssetEditorDialog.java @@ -0,0 +1,392 @@ +package com.ss.builder.fx.dialog.asset; + +import static com.ss.builder.Messages.ASSET_EDITOR_DIALOG_TITLE; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.preview.FilePreview; +import com.ss.builder.fx.preview.FilePreviewFactoryRegistry; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.preview.FilePreview; +import com.ss.builder.fx.preview.FilePreviewFactoryRegistry; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxUtils; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.value.ObservableBooleanValue; +import javafx.scene.control.Label; +import javafx.scene.control.TreeItem; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * The base implementation of the {@link AbstractSimpleEditorDialog} to choose some asset resource. + * + * @author JavaSaBr + */ +public class BaseAssetEditorDialog extends AbstractSimpleEditorDialog { + + @FunctionalInterface + public interface Validator { + + /** + * Return a string with error message if the object isn't valid or null if the object is ok. + * + * @param object the object to validate. + * @return the message or null. + */ + @FxThread + @Nullable String validate(@NotNull C object); + } + + /** + * The dialog. + */ + protected static final Point DIALOG_SIZE = new Point(-1, -1); + + /** + * The list of available previews. + */ + @NotNull + protected final Array previews; + + /** + * The function to handle the choose. + */ + @NotNull + protected final Consumer consumer; + + /** + * The function to validate the choose. + */ + @Nullable + private final Validator validator; + + /** + * The label with any warning. + */ + @NotNull + private final Label warningLabel; + + public BaseAssetEditorDialog(@NotNull Consumer consumer) { + this(consumer, null); + } + + public BaseAssetEditorDialog(@NotNull Consumer consumer, @Nullable Validator validator) { + this.consumer = consumer; + this.validator = validator; + this.warningLabel = new Label(); + this.previews = FilePreviewFactoryRegistry.getInstance() + .createAvailablePreviews(); + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + + var container = new HBox(); + + var firstPart = buildFirstPart(container); + firstPart.prefHeightProperty() + .bind(root.heightProperty()); + firstPart.prefWidthProperty() + .bind(root.widthProperty().multiply(0.5)); + + var secondPart = buildSecondPart(container); + secondPart.prefHeightProperty() + .bind(root.heightProperty()); + secondPart.prefWidthProperty() + .bind(root.widthProperty().multiply(0.5)); + + FxUtils.addClass(container, CssClasses.DEF_HBOX) + .addClass(root, CssClasses.ASSET_EDITOR_DIALOG); + + FxUtils.addChild(container, firstPart, secondPart) + .addChild(root, container); + } + + /** + * Build the first part of this dialog. + * + * @param container the horizontal container. + * @return the built component. + */ + @FxThread + protected @NotNull Region buildFirstPart(@NotNull HBox container) { + throw new RuntimeException("unsupported"); + } + + /** + * Get the target object from the asset element. + * + * @param element the asset element. + * @return the target object. + */ + @FxThread + protected @Nullable C getObject(@NotNull T element) { + throw new RuntimeException("unsupported"); + } + + /** + * Get the function to handle a choose. + * + * @return the function to handle a choose. + */ + @FromAnyThread + protected @NotNull Consumer getConsumer() { + return consumer; + } + + /** + * Handle selected element in the tree. + * + * @param newValue the new selected item. + */ + @FxThread + protected void processSelected(@Nullable TreeItem newValue) { + + var element = newValue == null ? null : newValue.getValue(); + var assetPath = element == null ? null : getAssetPath(element); + var realFile = element == null ? null : getRealFile(element); + + validate(getWarningLabel(), element); + try { + + if (assetPath != null) { + updatePreview(assetPath); + } else if (realFile != null) { + updatePreview(realFile); + } else { + updatePreview((String) null); + } + + } catch (Exception e) { + EditorUtils.handleException(LOGGER, this, e); + } + } + + /** + * Try to get an asset path from the element. + * + * @param element the element. + * @return the asset path or null. + */ + @FxThread + protected @Nullable String getAssetPath(@NotNull T element) { + return null; + } + + /** + * Try to get a real file from the element. + * + * @param element the element. + * @return the real file or null. + */ + @FxThread + protected @Nullable Path getRealFile(@NotNull T element) { + return null; + } + + /** + * Update the preview of the file. + * + * @param file the file. + */ + @FxThread + private void updatePreview(@NotNull Path file) { + + var previews = getPreviews(); + + var preview = previews.findAny(file, FilePreview::isSupport); + previews.forEach(preview, + (filePreview, toCheck) -> filePreview != toCheck, + (filePreview, toCheck) -> filePreview.hide()); + + if (preview == null) { + return; + } + + preview.show(file); + } + + /** + * Update the preview of the object by the asset path. + * + * @param assetPath the asset path of the object. + */ + @FxThread + private void updatePreview(@Nullable String assetPath) { + + var previews = getPreviews(); + + if (assetPath == null) { + previews.forEach(FilePreview::hide); + return; + } + + var preview = previews.findAny(assetPath, FilePreview::isSupport); + previews.forEach(preview, + (filePreview, toCheck) -> filePreview != toCheck, + (filePreview, toCheck) -> filePreview.hide()); + + if (preview == null) { + return; + } + + preview.show(assetPath); + } + + /** + * Validate the resource element. + * + * @param warningLabel the warning label + * @param element the element. + */ + @FxThread + protected void validate(@NotNull Label warningLabel, @Nullable T element) { + + var validator = getValidator(); + + if (validator == null) { + return; + } + + var object = element == null ? null : getObject(element); + var message = object == null ? null : validator.validate(object); + + if (message == null) { + warningLabel.setText(StringUtils.EMPTY); + warningLabel.setVisible(false); + } else { + warningLabel.setText(message); + warningLabel.setVisible(true); + } + } + + /** + * Build second part parent. + * + * @param container the container + * @return the parent + */ + @FxThread + protected @NotNull Region buildSecondPart(@NotNull HBox container) { + + var previewContainer = new StackPane(); + + previews.forEach(previewContainer, FilePreview::initialize); + + FxUtils.addClass(previewContainer, + CssClasses.ASSET_EDITOR_DIALOG_PREVIEW_CONTAINER); + + return previewContainer; + } + + /** + * Get the function to validate a choose. + * + * @return the function to validate a choose. + */ + @FxThread + protected @Nullable Validator getValidator() { + return validator; + } + + /** + * @return the label with any warning. + */ + @FxThread + protected @NotNull Label getWarningLabel() { + return notNull(warningLabel); + } + + /** + * Get the list of available file previews. + * + * @return the list of available file previews. + */ + @FxThread + protected @NotNull Array getPreviews() { + return notNull(previews); + } + + @Override + @FxThread + public void hide() { + getPreviews().forEach(FilePreview::release); + super.hide(); + } + + @Override + @FxThread + protected void createBeforeActions(@NotNull HBox container) { + super.createBeforeActions(container); + + warningLabel.setGraphic(new ImageView(Icons.WARNING_24)); + warningLabel.setVisible(false); + + FxUtils.addClass(warningLabel, CssClasses.DIALOG_LABEL_WARNING); + FxUtils.addChild(container, warningLabel); + } + + @Override + @FxThread + protected void createActions(@NotNull VBox root) { + super.createActions(root); + + var okButton = notNull(getOkButton()); + okButton.disableProperty().bind(buildDisableCondition()); + } + + /** + * Build disable condition. + * + * @return the disable condition. + */ + @FxThread + protected @NotNull BooleanBinding buildDisableCondition() { + return getWarningLabel().visibleProperty() + .or(buildAdditionalDisableCondition()); + } + + /** + * Build additional disable condition. + * + * @return the additional condition. + */ + @FxThread + protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { + throw new RuntimeException("unsupported"); + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.ASSET_EDITOR_DIALOG_TITLE; + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/file/AssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/file/AssetEditorDialog.java new file mode 100644 index 00000000..3f72feff --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/file/AssetEditorDialog.java @@ -0,0 +1,271 @@ +package com.ss.builder.fx.dialog.asset.file; + +import static com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory.createFor; +import static com.ss.builder.fx.util.UiUtils.findItemForValue; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory; +import com.ss.builder.fx.dialog.EditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.CreatedFileEvent; +import com.ss.builder.fx.event.impl.DeletedFileEvent; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.dialog.EditorDialog; +import com.ss.builder.fx.dialog.asset.BaseAssetEditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.CreatedFileEvent; +import com.ss.builder.fx.event.impl.DeletedFileEvent; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.fx.util.FxControlUtils; +import javafx.beans.value.ObservableBooleanValue; +import javafx.event.EventHandler; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * The implementation of the {@link EditorDialog} to choose the object from an asset folder. + * + * @param the type parameter + * @author JavaSaBr + */ +public class AssetEditorDialog extends BaseAssetEditorDialog { + + /** + * The handler created files events. + */ + @NotNull + private final EventHandler createdFileHandler = this::processEvent; + + /** + * The handler selected file events. + */ + @NotNull + private final EventHandler selectFileHandle = this::processEvent; + + /** + * The handler deleted file events, + */ + @NotNull + private final EventHandler deletedFileHandler = this::processEvent; + + /** + * The list of waited files to select. + */ + @NotNull + private final Array waitedFilesToSelect; + + /** + * The tree with all resources. + */ + @NotNull + private final ResourceTree resourceTree; + + public AssetEditorDialog(@NotNull Consumer consumer) { + this(consumer, null); + } + + public AssetEditorDialog(@NotNull Consumer consumer, @Nullable Validator validator) { + super(consumer, validator); + this.waitedFilesToSelect = ArrayFactory.newArray(Path.class); + this.resourceTree = new ResourceTree(this::processOpen, false); + } + + /** + * Set the list of available extensions. + * + * @param extensionFilter the list of available extensions. + */ + @FromAnyThread + public void setExtensionFilter(@NotNull Array extensionFilter) { + getResourceTree().setExtensionFilter(extensionFilter); + } + + /** + * Set the action tester. + * + * @param actionTester the action tester. + */ + @FromAnyThread + public void setActionTester(@Nullable Predicate> actionTester) { + getResourceTree().setActionTester(actionTester); + } + + /** + * Set true if need to show only folders. + * + * @param onlyFolders true if need to show only folders. + */ + @FromAnyThread + public void setOnlyFolders(boolean onlyFolders) { + getResourceTree().setOnlyFolders(onlyFolders); + } + + @Override + @FxThread + protected @NotNull Region buildFirstPart(@NotNull HBox container) { + FxControlUtils.onSelectedItemChange(resourceTree, this::processSelected); + return resourceTree; + } + + /** + * The process of opening the element. + * + * @param element the element + */ + @FxThread + protected void processOpen(@NotNull ResourceElement element) { + hide(); + } + + @Override + @FxThread + public void show(@NotNull Window owner) { + super.show(owner); + + var currentAsset = EditorConfig.getInstance() + .requiredCurrentAsset(); + + getResourceTree().fill(currentAsset); + + FxEventManager.getInstance() + .addEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler) + .addEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle) + .addEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); + + ExecutorManager.getInstance() + .addFxTask(resourceTree::requestFocus); + } + + /** + * Handle creating file event. + */ + @FxThread + private void processEvent(@NotNull CreatedFileEvent event) { + + var file = event.getFile(); + + var waitedFilesToSelect = getWaitedFilesToSelect(); + var waitedSelect = waitedFilesToSelect.contains(file); + + var resourceTree = getResourceTree(); + resourceTree.notifyCreated(file); + + if (waitedSelect) { + waitedFilesToSelect.fastRemove(file); + } + + if (waitedSelect || event.isNeedSelect()) { + resourceTree.expandTo(file, true); + } + } + + /** + * Handle deleting file event. + */ + @FxThread + private void processEvent(@NotNull DeletedFileEvent event) { + getResourceTree().notifyDeleted(event.getFile()); + } + + /** + * Handle selecting file event. + */ + @FxThread + private void processEvent(@NotNull RequestSelectFileEvent event) { + + var file = event.getFile(); + + var resourceTree = getResourceTree(); + var element = ResourceElementFactory.createFor(file); + var treeItem = UiUtils.findItemForValue(resourceTree.getRoot(), element); + + if (treeItem == null) { + getWaitedFilesToSelect().add(file); + return; + } + + resourceTree.expandTo(treeItem, true); + } + + /** + * Get the list of waited files to select. + * + * @return the list of waited files to select. + */ + @FromAnyThread + private @NotNull Array getWaitedFilesToSelect() { + return waitedFilesToSelect; + } + + @Override + @FxThread + protected @Nullable Path getRealFile(@NotNull ResourceElement element) { + return element.getFile(); + } + + @Override + @FxThread + public void hide() { + + FxEventManager.getInstance() + .removeEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler) + .removeEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle) + .removeEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); + + super.hide(); + } + + @Override + @FxThread + protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { + return getResourceTree().getSelectionModel() + .selectedItemProperty() + .isNull(); + } + + /** + * Get the tree with all resources. + * + * @return the tree with all resources. + */ + @FxThread + private @NotNull ResourceTree getResourceTree() { + return notNull(resourceTree); + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + + var selectedItem = getResourceTree().getSelectionModel().getSelectedItem(); + + if (selectedItem == null) { + hide(); + return; + } + + processOpen(selectedItem.getValue()); + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/file/FileAssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/file/FileAssetEditorDialog.java new file mode 100644 index 00000000..f9cf8065 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/file/FileAssetEditorDialog.java @@ -0,0 +1,61 @@ +package com.ss.builder.fx.dialog.asset.file; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.FolderResourceElement; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import javafx.scene.control.Label; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * The implementation of the {@link AssetEditorDialog} for choosing the {@link Path} from asset. + * + * @author JavaSaBr + */ +public class FileAssetEditorDialog extends AssetEditorDialog { + + public FileAssetEditorDialog(@NotNull Consumer consumer) { + super(consumer); + } + + public FileAssetEditorDialog(@NotNull Consumer consumer, @Nullable Validator validator) { + super(consumer, validator); + } + + @Override + @FxThread + protected void processOpen(@NotNull ResourceElement element) { + super.processOpen(element); + getConsumer().accept(element.getFile()); + } + + @Override + @FxThread + protected @Nullable Path getObject(@NotNull ResourceElement element) { + return element.getFile(); + } + + @Override + @FxThread + protected void validate(@NotNull Label warningLabel, @Nullable ResourceElement element) { + super.validate(warningLabel, element); + + var validator = getValidator(); + var visible = warningLabel.isVisible(); + + if (!visible && element instanceof FolderResourceElement) { + warningLabel.setText(Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE); + warningLabel.setVisible(true); + } else if (validator == null) { + warningLabel.setVisible(false); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/file/FolderAssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/file/FolderAssetEditorDialog.java new file mode 100644 index 00000000..e8078b21 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/file/FolderAssetEditorDialog.java @@ -0,0 +1,42 @@ +package com.ss.builder.fx.dialog.asset.file; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * The implementation of the {@link AssetEditorDialog} to choose the {@link Path} from asset. + * + * @author JavaSaBr + */ +public class FolderAssetEditorDialog extends AssetEditorDialog { + + public FolderAssetEditorDialog(@NotNull Consumer consumer) { + super(consumer); + setOnlyFolders(true); + } + + public FolderAssetEditorDialog(@NotNull Consumer consumer, @Nullable Validator validator) { + super(consumer, validator); + setOnlyFolders(true); + } + + @Override + @FxThread + protected void processOpen(@NotNull ResourceElement element) { + super.processOpen(element); + getConsumer().accept(element.getFile()); + } + + @Override + @FxThread + protected @Nullable Path getObject(@NotNull ResourceElement element) { + return element.getFile(); + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/virtual/StringVirtualAssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/virtual/StringVirtualAssetEditorDialog.java new file mode 100644 index 00000000..1b2f8104 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/virtual/StringVirtualAssetEditorDialog.java @@ -0,0 +1,50 @@ +package com.ss.builder.fx.dialog.asset.virtual; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * The implementation to work with string resources. + * + * @author JavaSaBr + */ +public class StringVirtualAssetEditorDialog extends VirtualAssetEditorDialog { + + public static final Validator DEFAULT_VALIDATOR = resource -> { + + var extension = FileUtils.getExtension(resource); + + if (StringUtils.isEmpty(extension)) { + return Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE; + } + + return null; + }; + + public StringVirtualAssetEditorDialog(@NotNull Consumer consumer, @NotNull Array resources) { + this(consumer, DEFAULT_VALIDATOR, resources); + } + + public StringVirtualAssetEditorDialog( + @NotNull Consumer consumer, + @Nullable Validator validator, + @NotNull Array resources + ) { + super(consumer, validator, resources); + } + + @Override + @FromAnyThread + protected @NotNull Class getObjectsType() { + return String.class; + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/asset/virtual/VirtualAssetEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/asset/virtual/VirtualAssetEditorDialog.java new file mode 100644 index 00000000..b3ed7020 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/asset/virtual/VirtualAssetEditorDialog.java @@ -0,0 +1,178 @@ +package com.ss.builder.fx.dialog.asset.virtual; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElementFactory; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.virtual.tree.VirtualResourceTree; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElement; +import com.ss.builder.fx.component.virtual.tree.resource.VirtualResourceElementFactory; +import com.ss.builder.fx.dialog.asset.BaseAssetEditorDialog; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxControlUtils; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.value.ObservableBooleanValue; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * The implementation of the {@link BaseAssetEditorDialog} to choose the object from a virtual asset. + * + * @param the type parameter + * @author JavaSaBr + */ +public class VirtualAssetEditorDialog extends BaseAssetEditorDialog, C> { + + /** + * The all resources. + */ + @NotNull + private final Array resources; + + /** + * The tree with all resources. + */ + @NotNull + private final VirtualResourceTree resourceTree; + + public VirtualAssetEditorDialog(@NotNull Consumer consumer, @NotNull Array resources) { + this(consumer, null, resources); + } + + public VirtualAssetEditorDialog( + @NotNull Consumer consumer, + @Nullable Validator validator, + @NotNull Array resources + ) { + super(consumer, validator); + this.resources = resources; + this.resourceTree = new VirtualResourceTree<>(getObjectsType()); + } + + /** + * @param pathFunction the path function. + * @see VirtualResourceTree#setPathFunction(Function) + */ + @FromAnyThread + public void setPathFunction(@Nullable Function pathFunction) { + getResourceTree().setPathFunction(pathFunction); + } + + @Override + @FxThread + protected @Nullable String getAssetPath(@NotNull VirtualResourceElement element) { + return getResourceTree().getPath(element.getObject()); + } + + @Override + @FxThread + protected @NotNull Region buildFirstPart(@NotNull HBox container) { + FxControlUtils.onSelectedItemChange(resourceTree, this::processSelected); + return resourceTree; + } + + /** + * Get the type of presented objects. + * + * @return the type of presented objects. + */ + @FromAnyThread + protected @NotNull Class getObjectsType() { + throw new RuntimeException("unsupported"); + } + + @Override + @FxThread + public void show(@NotNull final Window owner) { + super.show(owner); + + var resourceTree = getResourceTree(); + var newRoot = VirtualResourceElementFactory.build(resources, resourceTree); + + resourceTree.fill(newRoot); + resourceTree.expandAll(); + + ExecutorManager.getInstance() + .addFxTask(resourceTree::requestFocus); + } + + @Override + @FxThread + protected @Nullable C getObject(@NotNull VirtualResourceElement element) { + var object = element.getObject(); + var type = getObjectsType(); + return type.isInstance(object) ? type.cast(object) : null; + } + + /** + * Get the tree with all resources. + * + * @return the tree with all resources. + */ + @FxThread + private @NotNull VirtualResourceTree getResourceTree() { + return notNull(resourceTree); + } + + @Override + @FxThread + protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { + + var resourceTree = getResourceTree(); + var selectedItemProperty = resourceTree.getSelectionModel() + .selectedItemProperty(); + + var type = getObjectsType(); + var typeCondition = new BooleanBinding() { + + @Override + protected boolean computeValue() { + var treeItem = selectedItemProperty.get(); + return treeItem == null || !type.isInstance(treeItem.getValue().getObject()); + } + + @Override + public Boolean getValue() { + return computeValue(); + } + }; + + return Bindings.or(selectedItemProperty.isNull(), typeCondition); + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + + var selectedItem = getResourceTree() + .getSelectionModel() + .getSelectedItem(); + + if (selectedItem == null) { + hide(); + return; + } + + var element = selectedItem.getValue(); + var object = element.getObject(); + var type = getObjectsType(); + + if (type.isInstance(object)) { + getConsumer().accept(type.cast(object)); + } + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/file/chooser/ExternalFileEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/file/chooser/ExternalFileEditorDialog.java similarity index 89% rename from src/main/java/com/ss/editor/ui/dialog/file/chooser/ExternalFileEditorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/file/chooser/ExternalFileEditorDialog.java index b67acba0..bac0fc2f 100644 --- a/src/main/java/com/ss/editor/ui/dialog/file/chooser/ExternalFileEditorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/file/chooser/ExternalFileEditorDialog.java @@ -1,15 +1,15 @@ -package com.ss.editor.ui.dialog.file.chooser; +package com.ss.builder.fx.dialog.file.chooser; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.component.asset.tree.ResourceTree; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.dialog.EditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.dialog.EditorDialog; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -61,7 +61,7 @@ public class ExternalFileEditorDialog extends AbstractSimpleEditorDialog { @Nullable protected Path initDirectory; - public ExternalFileEditorDialog(@NotNull final Consumer<@NotNull Path> consumer) { + public ExternalFileEditorDialog(@NotNull Consumer<@NotNull Path> consumer) { this.consumer = consumer; } diff --git a/src/main/java/com/ss/editor/ui/dialog/file/chooser/OpenExternalFolderEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/file/chooser/OpenExternalFolderEditorDialog.java similarity index 82% rename from src/main/java/com/ss/editor/ui/dialog/file/chooser/OpenExternalFolderEditorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/file/chooser/OpenExternalFolderEditorDialog.java index 9444a28a..b2589187 100644 --- a/src/main/java/com/ss/editor/ui/dialog/file/chooser/OpenExternalFolderEditorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/file/chooser/OpenExternalFolderEditorDialog.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.dialog.file.chooser; +package com.ss.builder.fx.dialog.file.chooser; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.dialog.EditorDialog; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.dialog.EditorDialog; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/dialog/geometry/GeometrySelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/geometry/GeometrySelectorDialog.java new file mode 100644 index 00000000..63ea2572 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/geometry/GeometrySelectorDialog.java @@ -0,0 +1,32 @@ +package com.ss.builder.fx.dialog.geometry; + +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.dialog.node.selector.NodeSelectorDialog; + +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * The implementation of node selector dialog to select a geometry. + * + * @author JavaSaBr + */ +public class GeometrySelectorDialog extends NodeSelectorDialog { + + public GeometrySelectorDialog(@NotNull final Spatial model, @NotNull final Consumer handler) { + super(model, Geometry.class, handler); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.GEOMETRY_SELECTOR_DIALOG_TITLE; + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/geometry/lod/GenerateLodLevelsDialog.java b/src/main/java/com/ss/builder/fx/dialog/geometry/lod/GenerateLodLevelsDialog.java similarity index 87% rename from src/main/java/com/ss/editor/ui/dialog/geometry/lod/GenerateLodLevelsDialog.java rename to src/main/java/com/ss/builder/fx/dialog/geometry/lod/GenerateLodLevelsDialog.java index 70068aff..9371e62d 100644 --- a/src/main/java/com/ss/editor/ui/dialog/geometry/lod/GenerateLodLevelsDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/geometry/lod/GenerateLodLevelsDialog.java @@ -1,24 +1,37 @@ -package com.ss.editor.ui.dialog.geometry.lod; +package com.ss.builder.fx.dialog.geometry.lod; -import static com.ss.editor.ui.FxConstants.DIALOG_LIST_WIDTH_PERCENT; +import static com.ss.builder.fx.FxConstants.DIALOG_LIST_WIDTH_PERCENT; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static javafx.collections.FXCollections.observableArrayList; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.fx.util.FXUtils; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; @@ -190,16 +203,16 @@ protected void createContent(@NotNull final VBox root) { levelsList = new ListView<>(); levelsList.setCellFactory(param -> new LodValueCell(this)); levelsList.setEditable(true); - levelsList.prefWidthProperty().bind(widthProperty().multiply(DIALOG_LIST_WIDTH_PERCENT)); - levelsList.maxWidthProperty().bind(widthProperty().multiply(DIALOG_LIST_WIDTH_PERCENT)); + levelsList.prefWidthProperty().bind(widthProperty().multiply(FxConstants.DIALOG_LIST_WIDTH_PERCENT)); + levelsList.maxWidthProperty().bind(widthProperty().multiply(FxConstants.DIALOG_LIST_WIDTH_PERCENT)); levelsList.getItems().addListener((ListChangeListener) c -> updateButtonOk()); levelsList.setFixedCellSize(FxConstants.LIST_CELL_HEIGHT); FXUtils.addToPane(levelsList, root); final HBox buttonContainer = new HBox(); - buttonContainer.prefWidthProperty().bind(widthProperty().multiply(DIALOG_LIST_WIDTH_PERCENT)); - buttonContainer.maxWidthProperty().bind(widthProperty().multiply(DIALOG_LIST_WIDTH_PERCENT)); + buttonContainer.prefWidthProperty().bind(widthProperty().multiply(FxConstants.DIALOG_LIST_WIDTH_PERCENT)); + buttonContainer.maxWidthProperty().bind(widthProperty().multiply(FxConstants.DIALOG_LIST_WIDTH_PERCENT)); final Button addButton = new Button(); addButton.setGraphic(new ImageView(Icons.ADD_12)); diff --git a/src/main/java/com/ss/editor/ui/dialog/geometry/lod/LodValueCell.java b/src/main/java/com/ss/builder/fx/dialog/geometry/lod/LodValueCell.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/geometry/lod/LodValueCell.java rename to src/main/java/com/ss/builder/fx/dialog/geometry/lod/LodValueCell.java index fadfd7c7..98e36edf 100644 --- a/src/main/java/com/ss/editor/ui/dialog/geometry/lod/LodValueCell.java +++ b/src/main/java/com/ss/builder/fx/dialog/geometry/lod/LodValueCell.java @@ -1,9 +1,11 @@ -package com.ss.editor.ui.dialog.geometry.lod; +package com.ss.builder.fx.dialog.geometry.lod; import com.jme3.scene.Mesh; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.dialog.geometry.lod.GenerateLodLevelsDialog.ReductionMethod; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.dialog.geometry.lod.GenerateLodLevelsDialog.ReductionMethod; +import com.ss.builder.fx.util.UiUtils; import javafx.scene.control.cell.TextFieldListCell; import javafx.util.StringConverter; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/dialog/imports/model/ModelImportDialog.java b/src/main/java/com/ss/builder/fx/dialog/imports/model/ModelImportDialog.java new file mode 100644 index 00000000..b27a23a2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/imports/model/ModelImportDialog.java @@ -0,0 +1,453 @@ +package com.ss.builder.fx.dialog.imports.model; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION; +import static com.ss.editor.extension.property.EditablePropertyType.*; +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.builder.util.EditorUtils.toAssetPath; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.nio.file.StandardOpenOption.*; +import com.jme3.asset.AssetKey; +import com.jme3.asset.MaterialKey; +import com.jme3.asset.TextureKey; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.material.MatParam; +import com.jme3.material.MatParamTexture; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.texture.Texture; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.asset.locator.FileSystemAssetLocator; +import com.ss.builder.jme.asset.locator.FolderAssetLocator; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.JmeFilePreviewManager; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.util.TangentGenerator; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.asset.locator.FileSystemAssetLocator; +import com.ss.builder.jme.asset.locator.FolderAssetLocator; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.JmeFilePreviewManager; +import com.ss.builder.plugin.api.file.creator.GenericFileCreator; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; +import com.ss.builder.util.NodeUtils; +import com.ss.builder.util.TangentGenerator; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.function.Function; + +/** + * The implementation of a dialog to import external models. + * + * @author JavaSaBr + */ +public class ModelImportDialog extends GenericFileCreator { + + private static final String PROP_FILE = "file"; + private static final String PROP_NEED_MATERIALS_EXPORT = "needMaterialsExport"; + private static final String PROP_MATERIALS_FOLDER = "materialsFolder"; + private static final String PROP_OVERWRITE_MATERIALS = "overwriteMaterials"; + private static final String PROP_OVERWRITE_TEXTURES = "overwriteTextures"; + private static final String PROP_TEXTURES_FOLDER = "texturesFolder"; + + private static final Array MATERIAL_EXPORT_DEPS = ArrayFactory.asArray(PROP_NEED_MATERIALS_EXPORT); + + /** + * The image view to show preview of model. + */ + @NotNull + private final ImageView imageView; + + /** + * The rendered file. + */ + @Nullable + private Path renderedFile; + + public ModelImportDialog() { + this.imageView = new ImageView(); + setTitleText(Messages.IMPORT_MODEL_DIALOG_TITLE); + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_IMPORT; + } + + @Override + @FromAnyThread + protected @NotNull Array getPropertyDefinitions() { + + var result = Array.ofType(PropertyDefinition.class); + result.add(new PropertyDefinition(EXTERNAL_FILE, Messages.IMPORT_MODEL_DIALOG_EXTERNAL_FILE, PROP_FILE, null)); + result.add(new PropertyDefinition(FOLDER_FROM_ASSET_FOLDER, Messages.IMPORT_MODEL_DIALOG_TEXTURES_FOLDER, PROP_TEXTURES_FOLDER, null)); + result.add(new PropertyDefinition(BOOLEAN, Messages.IMPORT_MODEL_DIALOG_OVERWRITE_TEXTURES, PROP_OVERWRITE_TEXTURES, true)); + result.add(new PropertyDefinition(BOOLEAN, Messages.MODEL_CONVERTER_DIALOG_EXPORT_MATERIALS, PROP_NEED_MATERIALS_EXPORT, false)); + result.add(new PropertyDefinition(FOLDER_FROM_ASSET_FOLDER, MATERIAL_EXPORT_DEPS, Messages.MODEL_CONVERTER_DIALOG_MATERIAL_FOLDER, PROP_MATERIALS_FOLDER, null)); + result.add(new PropertyDefinition(BOOLEAN, MATERIAL_EXPORT_DEPS, Messages.MODEL_CONVERTER_DIALOG_OVERWRITE_MATERIALS, PROP_OVERWRITE_MATERIALS, false)); + + return result; + } + + @Override + @FxThread + protected void createPreview(@NotNull BorderPane container) { + super.createPreview(container); + + imageView.fitHeightProperty() + .bind(container.heightProperty().subtract(4)); + imageView.fitWidthProperty() + .bind(container.widthProperty().subtract(4)); + + container.setCenter(imageView); + } + + @Override + @FromAnyThread + protected boolean needPreview() { + return true; + } + + /** + * Get the image view. + * + * @return the image view. + */ + @FxThread + private @NotNull ImageView getImageView() { + return notNull(imageView); + } + + @Override + @FxThread + protected boolean validate(@NotNull VarTable vars) { + + var imageView = getImageView(); + + if (!vars.has(PROP_FILE)) { + imageView.setImage(null); + return false; + } + + var file = vars.get(PROP_FILE, Path.class); + + if (!JmeFilePreviewManager.isModelFile(file)) { + imageView.setImage(null); + return false; + } + + var renderedFile = getRenderedFile(); + if (file.equals(renderedFile)) { + return super.validate(vars); + } + + var width = (int) imageView.getFitWidth(); + var height = (int) imageView.getFitHeight(); + + var previewManager = JmeFilePreviewManager.getInstance(); + previewManager.showExternal(file, width, height); + + var sourceView = previewManager.getImageView(); + var imageProperty = imageView.imageProperty(); + imageProperty.bind(sourceView.imageProperty()); + + setRenderedFile(file); + + return super.validate(vars); + } + + @Override + @FxThread + protected void processOk() { + hide(); + + UiUtils.incrementLoading(); + + ExecutorManager.getInstance() + .addBackgroundTask(this::startImportInBackground); + } + + /** + * Start importing model in background. + */ + @BackgroundThread + private void startImportInBackground() { + try { + importModelInBackground(); + } finally { + UiUtils.decrementLoading(); + } + } + + @Override + @FromAnyThread + protected @NotNull String getFileExtension() { + return FileExtensions.JME_OBJECT; + } + + /** + * Import the external model in a background thread. + */ + @BackgroundThread + private void importModelInBackground() { + + var editorConfig = EditorConfig.getInstance(); + var modelFile = notNull(getFileToCreate()); + var parent = modelFile.getParent(); + var importedFile = vars.get(PROP_FILE, Path.class); + var assetManager = EditorUtils.getAssetManager(); + + Spatial model; + + FolderAssetLocator.setIgnore(true); + try { + model = assetManager.loadModel(importedFile.toString()); + } finally { + FolderAssetLocator.setIgnore(false); + } + + if (editorConfig.getBoolean(DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION, DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION)) { + TangentGenerator.useMikktspaceGenerator(model); + } + + var texturesFolder = vars.get(PROP_TEXTURES_FOLDER, parent); + var overwriteTextures = vars.getBoolean(PROP_OVERWRITE_TEXTURES); + + var needExportMaterials = vars.getBoolean(PROP_NEED_MATERIALS_EXPORT); + var materialsFolder = vars.get(PROP_MATERIALS_FOLDER, parent); + var overwriteMaterials = vars.getBoolean(PROP_OVERWRITE_MATERIALS, false); + + var textures = Array.ofType(Texture.class); + var geometries = Array.ofType(Geometry.class); + + NodeUtils.visitGeometry(model, geometry -> { + + var material = geometry.getMaterial(); + + if (needExportMaterials) { + geometries.add(geometry); + } + + material.getParams().stream() + .filter(MatParamTexture.class::isInstance) + .map(MatParam::getValue) + .filter(Texture.class::isInstance) + .map(Texture.class::cast) + .filter(texture -> texture.getKey() != null) + .forEach(textures::add); + }); + + copyTextures(texturesFolder, overwriteTextures, textures); + + if (needExportMaterials) { + exportMaterials(materialsFolder, overwriteMaterials, geometries); + } + + var assetFile = notNull(EditorUtils.getAssetFile(modelFile)); + var assetPath = EditorUtils.toAssetPath(assetFile); + + model.setName(assetPath); + + var exporter = BinaryExporter.getInstance(); + + try (var out = Files.newOutputStream(modelFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + exporter.save(model, out); + } catch (final IOException e) { + throw new RuntimeException(e); + } + + notifyFileCreated(modelFile, true); + } + + /** + * Export all embedded materials from the external model. + * + * @param materialsFolder the materials folder. + * @param overwriteMaterials true if we can overwrite existing materials. + * @param geometries the found geometries in the model. + */ + @BackgroundThread + private void exportMaterials( + @NotNull Path materialsFolder, + boolean overwriteMaterials, + @NotNull Array geometries + ) { + + if (geometries.isEmpty()) { + return; + } + + var resultNameToKey = ObjectDictionary.ofType(String.class); + + for (var geometry : geometries) { + + var material = geometry.getMaterial(); + var originalName = material.getName(); + var name = StringUtils.isEmpty(geometry.getName()) ? "geom" : geometry.getName(); + var resultName = StringUtils.isEmpty(originalName) ? "embedded-mat-" + name : originalName; + + var newKey = resultNameToKey.get(resultName); + + if (newKey != null) { + material.setKey(new MaterialKey(newKey)); + continue; + } + + var resultFile = materialsFolder.resolve(resultName + "." + FileExtensions.JME_MATERIAL); + + if (!Files.exists(resultFile) || overwriteMaterials) { + try (var pout = new PrintWriter(Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE))) { + pout.println(MaterialSerializer.serializeToString(material)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + var assetFile = notNull(EditorUtils.getAssetFile(resultFile)); + var assetPath = EditorUtils.toAssetPath(assetFile); + + material.setKey(new MaterialKey(assetPath)); + resultNameToKey.put(resultName, assetPath); + } + } + + /** + * Copy textures from the external model. + * + * @param texturesFolder the textures folder. + * @param overwriteTextures true if need to overwrite existing textures. + * @param textures the found textures. + */ + @BackgroundThread + private void copyTextures( + @NotNull Path texturesFolder, + boolean overwriteTextures, + @NotNull Array textures) { + + if (textures.isEmpty()) { + return; + } + + var oldKeyToNew = ObjectDictionary.ofType(String.class); + var newTextureKeys = Array.ofType(AssetKey.class); + + for (var texture : textures) { + + var textureKey = (TextureKey) texture.getKey(); + if (newTextureKeys.contains(textureKey)) { + continue; + } + + var newKey = oldKeyToNew.get(textureKey.getName(), + makeCopyTextureFunction(texturesFolder, overwriteTextures)); + + var newTextureKey = new TextureKey(newKey, textureKey.isFlipY()); + newTextureKey.setGenerateMips(textureKey.isGenerateMips()); + newTextureKey.setTextureTypeHint(textureKey.getTextureTypeHint()); + + texture.setKey(newTextureKey); + newTextureKeys.add(newTextureKey); + } + } + + /** + * Create the copy texture function. + * + * @param texturesFolder the textures folder. + * @param overwriteTextures true if we can overwrite existing textures. + * @return the new asset path. + */ + @FromAnyThread + private @NotNull Function makeCopyTextureFunction( + @NotNull Path texturesFolder, + boolean overwriteTextures) + { + return oldPath -> { + + var textureFile = Paths.get(oldPath); + var fileName = textureFile.getFileName(); + + var newTextureFile = texturesFolder.resolve(fileName); + var assetFile = notNull(EditorUtils.getAssetFile(newTextureFile)); + var assetPath = EditorUtils.toAssetPath(assetFile); + + if (Files.exists(newTextureFile) && !overwriteTextures) { + return assetPath; + } + + try { + Files.copy(textureFile, newTextureFile, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return assetPath; + }; + } + + /** + * Set the rendered file. + * + * @param renderedFile the rendered file. + */ + @FxThread + private void setRenderedFile(@Nullable Path renderedFile) { + this.renderedFile = renderedFile; + } + + /** + * Get the rendered file. + * + * @return the rendered file. + */ + @FxThread + private @Nullable Path getRenderedFile() { + return renderedFile; + } + + @Override + @FxThread + public void hide() { + + var previewManager = JmeFilePreviewManager.getInstance(); + previewManager.clear(); + + FileSystemAssetLocator.clear(); + + super.hide(); + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/node/selector/LightSelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/node/selector/LightSelectorDialog.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/node/selector/LightSelectorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/node/selector/LightSelectorDialog.java index 99a46558..24cd5479 100644 --- a/src/main/java/com/ss/editor/ui/dialog/node/selector/LightSelectorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/node/selector/LightSelectorDialog.java @@ -1,9 +1,9 @@ -package com.ss.editor.ui.dialog.node.selector; +package com.ss.builder.fx.dialog.node.selector; import com.jme3.light.Light; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; diff --git a/src/main/java/com/ss/editor/ui/dialog/node/selector/NodeSelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/node/selector/NodeSelectorDialog.java similarity index 91% rename from src/main/java/com/ss/editor/ui/dialog/node/selector/NodeSelectorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/node/selector/NodeSelectorDialog.java index c70375d9..31d95985 100644 --- a/src/main/java/com/ss/editor/ui/dialog/node/selector/NodeSelectorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/node/selector/NodeSelectorDialog.java @@ -1,14 +1,14 @@ -package com.ss.editor.ui.dialog.node.selector; +package com.ss.builder.fx.dialog.node.selector; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.control.model.ModelNodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.array.Array; import javafx.scene.control.Button; diff --git a/src/main/java/com/ss/editor/ui/dialog/node/selector/SpatialSelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/node/selector/SpatialSelectorDialog.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/node/selector/SpatialSelectorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/node/selector/SpatialSelectorDialog.java index 1b67a608..9fc60067 100644 --- a/src/main/java/com/ss/editor/ui/dialog/node/selector/SpatialSelectorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/node/selector/SpatialSelectorDialog.java @@ -1,8 +1,8 @@ -package com.ss.editor.ui.dialog.node.selector; +package com.ss.builder.fx.dialog.node.selector; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; diff --git a/src/main/java/com/ss/builder/fx/dialog/plugin/PluginListCell.java b/src/main/java/com/ss/builder/fx/dialog/plugin/PluginListCell.java new file mode 100644 index 00000000..a7fd649b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/plugin/PluginListCell.java @@ -0,0 +1,50 @@ +package com.ss.builder.fx.dialog.plugin; + +import com.ss.builder.plugin.EditorPlugin; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.plugin.EditorPlugin; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ListCell; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of {@link ListCell} to present a plugin. + * + * @author JavaSaBr + */ +public class PluginListCell extends ListCell { + + /** + * The icon. + */ + @NotNull + private final ImageView icon; + + public PluginListCell() { + this.icon = new ImageView(Icons.PLUGIN_16); + FxUtils.addClass(this, CssClasses.PLUGIN_LIST_CELL); + DynamicIconSupport.updateListener(this, icon, selectedProperty()); + } + + @Override + protected void updateItem(@Nullable EditorPlugin item, boolean empty) { + super.updateItem(item, empty); + + if(item == null) { + setGraphic(null); + setText(StringUtils.EMPTY); + return; + } + + setText(item.getName()); + setGraphic(icon); + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/plugin/PluginsDialog.java b/src/main/java/com/ss/builder/fx/dialog/plugin/PluginsDialog.java new file mode 100644 index 00000000..d2575e02 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/plugin/PluginsDialog.java @@ -0,0 +1,481 @@ +package com.ss.builder.fx.dialog.plugin; + +import static com.ss.builder.fx.util.UiUtils.toWeb; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.PluginManager; +import com.ss.builder.plugin.EditorPlugin; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.analytics.google.GAEvent; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.PluginManager; +import com.ss.builder.plugin.EditorPlugin; +import com.ss.builder.fx.FxConstants; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.dialog.ConfirmDialog; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.application.Platform; +import javafx.scene.control.Button; +import javafx.scene.control.ListView; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Background; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.paint.Color; +import javafx.scene.web.WebView; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.io.File; +import java.util.Arrays; + +/** + * The implementation of a dialog to work with plugins. + * + * @author JavaSaBr + */ +public class PluginsDialog extends AbstractSimpleEditorDialog { + + private static final Point DIALOG_SIZE = new Point(1200, -1); + + private static final PluginManager PLUGIN_MANAGER = PluginManager.getInstance(); + + /** + * The original list of installed plugins. + */ + @NotNull + private final Array originalIds; + + /** + * The list of installed plugins. + */ + @NotNull + private final ListView pluginListView; + + /** + * The description area. + */ + @NotNull + private final WebView descriptionArea; + + /** + * The remove button. + */ + @NotNull + private final Button removeButton; + + /** + * The background color. + */ + @Nullable + private Color backgroundColor; + + /** + * The font color. + */ + @Nullable + private Color fontColor; + + /** + * The link color. + */ + @Nullable + private Color linkColor; + + public PluginsDialog() { + this.originalIds = Array.ofType(String.class); + this.pluginListView = new ListView<>(); + this.descriptionArea = new WebView(); + this.removeButton = new Button(); + PLUGIN_MANAGER.handlePluginsNow(plugin -> originalIds.add(plugin.getId())); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + refreshPlugins(); + } + + @Override + @FxThread + protected void createContent(@NotNull GridPane root) { + super.createContent(root); + + pluginListView.setCellFactory(param -> new PluginListCell()); + pluginListView.setFixedCellSize(FxConstants.LIST_CELL_HEIGHT); + pluginListView.prefWidthProperty().bind(root.widthProperty().divide(2)); + pluginListView.prefHeightProperty().bind(root.heightProperty()); + + var descriptionContainer = new BorderPane(descriptionArea); + descriptionContainer.setVisible(false); + descriptionContainer.prefWidthProperty() + .bind(root.widthProperty().divide(2)); + descriptionContainer.backgroundProperty() + .addListener((observable, oldValue, newValue) -> takeColors(newValue)); + + var buttonContainer = new HBox(); + + var addButton = new Button(); + addButton.setGraphic(new ImageView(Icons.ADD_12)); + addButton.setOnAction(event -> processAdd()); + + removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); + removeButton.setOnAction(event -> processRemove()); + removeButton.setDisable(true); + + FxControlUtils.onSelectedItemChange(pluginListView, this::onSelected); + + FxUtils.addClass(buttonContainer, CssClasses.DEF_HBOX) + .addClass(addButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER) + .addClass(removeButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER) + .addClass(root, CssClasses.PLUGINS_DIALOG) + .addClass(descriptionContainer, CssClasses.WEBVIEW_TEXT_AREA); + + DynamicIconSupport.addSupport(addButton, removeButton); + + root.add(pluginListView, 0, 0, 1, 1); + root.add(descriptionContainer, 1, 0, 1, 1); + root.add(buttonContainer, 0, 1, 1, 1); + + FxUtils.addChild(buttonContainer, addButton, removeButton); + } + + /** + * Take CSS colors from background. + * + * @param newValue the new background. + */ + private void takeColors(@Nullable Background newValue) { + + if (newValue == null) { + setBackgroundColor(null); + setFontColor(null); + return; + } + + var fills = newValue.getFills(); + if (fills.size() < 3) { + setBackgroundColor(null); + setFontColor(null); + return; + } + + var background = fills.get(0).getFill(); + var font = fills.get(1).getFill(); + var link = fills.get(2).getFill(); + + if (background instanceof Color) { + setBackgroundColor((Color) background); + } + + if (font instanceof Color) { + setFontColor((Color) font); + } + + if (link instanceof Color) { + setLinkColor((Color) link); + } + } + + /** + * Get the background color. + * + * @return the background color. + */ + private @Nullable Color getBackgroundColor() { + return backgroundColor; + } + + /** + * Set the background color. + * + * @param backgroundColor the background color. + */ + private void setBackgroundColor(@Nullable Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + /** + * Get the font color. + * + * @return the font color. + */ + private @Nullable Color getFontColor() { + return fontColor; + } + + /** + * Set the font color. + * + * @param fontColor the font color. + */ + private void setFontColor(@Nullable Color fontColor) { + this.fontColor = fontColor; + } + + /** + * Get the link color. + * + * @return the link color. + */ + private @Nullable Color getLinkColor() { + return linkColor; + } + + /** + * Set the link color. + * + * @param linkColor the link color. + */ + private void setLinkColor(@Nullable Color linkColor) { + this.linkColor = linkColor; + } + + /** + * Get the remove button. + * + * @return the remove button. + */ + private @NotNull Button getRemoveButton() { + return notNull(removeButton); + } + + /** + * Get the description area. + * + * @return the description area. + */ + private @NotNull WebView getDescriptionArea() { + return notNull(descriptionArea); + } + + /** + * Handle the selected plugin. + * + * @param newValue the new selected plugin. + */ + @FxThread + private void onSelected(@Nullable EditorPlugin newValue) { + + getRemoveButton().setDisable(newValue == null || newValue.isEmbedded()); + + var descriptionArea = getDescriptionArea(); + descriptionArea.getParent().setVisible(newValue != null); + descriptionArea.getEngine().loadContent(generateDescription(newValue)); + } + + /** + * Generate HTML description. + * + * @param plugin the plugin. + * @return the html description. + */ + private @NotNull String generateDescription(@Nullable EditorPlugin plugin) { + + if (plugin == null) { + return StringUtils.EMPTY; + } + + var name = plugin.getName(); + var version = plugin.getVersion(); + var description = plugin.getDescription(); + var homePageUrl = plugin.getHomePageUrl(); + var usedGradleDependencies = plugin.getUsedGradleDependencies(); + var usedMavenDependencies = plugin.getUsedMavenDependencies(); + + var result = new StringBuilder(""); + + var backgroundColor = getBackgroundColor(); + var fontColor = getFontColor(); + var linkColor = getLinkColor(); + + if (backgroundColor != null && fontColor != null && linkColor != null) { + result.append(""); + result.append(""); + } + + result.append(""); + result.append("

").append(name).append("

"); + result.append("

").append(Messages.PLUGINS_DIALOG_VERSION).append(": ").append(version).append("

"); + result.append("

").append(description).append("

"); + + if (homePageUrl != null) { + result.append("

").append(Messages.PLUGINS_DIALOG_HOME_PAGE).append("

"); + } + + if (StringUtils.isNotEmpty(usedGradleDependencies) || StringUtils.isNotEmpty(usedMavenDependencies)) { + result.append("

").append(Messages.PLUGINS_DIALOG_USED_DEPENDENCIES).append(":").append("

"); + + if (StringUtils.isNotEmpty(usedGradleDependencies)) { + result.append("

").append("Gradle:").append("

"); + result.append(usedGradleDependencies); + } + + if (StringUtils.isNotEmpty(usedMavenDependencies)) { + result.append("

").append("Maven:").append("

"); + result.append(usedMavenDependencies); + } + } + + result.append(""); + + return result.toString(); + } + + @Override + @FromAnyThread + protected boolean isGridStructure() { + return true; + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return Messages.PLUGINS_DIALOG_TITLE; + } + + /** + * Get the list of installed plugins. + * + * @return the list of installed plugins. + */ + @FxThread + private @NotNull ListView getPluginListView() { + return notNull(pluginListView); + } + + /** + * Refresh the list of installed plugins. + */ + @FxThread + private void refreshPlugins() { + + var items = getPluginListView().getItems(); + items.clear(); + + PLUGIN_MANAGER.handlePluginsNow(items::add); + } + + /** + * Process remove. + */ + @FxThread + private void processRemove() { + + var toRemove = getPluginListView() + .getSelectionModel() + .getSelectedItem(); + + if (toRemove.isEmbedded()) { + return; + } + + PLUGIN_MANAGER.removePlugin(toRemove); + + refreshPlugins(); + } + + /** + * Get the list of original plugin ids. + * + * @return the list of original plugin ids. + */ + @FxThread + private @NotNull Array getOriginalIds() { + return originalIds; + } + + @Override + @FxThread + protected void processClose() { + super.processClose(); + + var newIds = ArrayFactory.newArray(String.class); + + PLUGIN_MANAGER.handlePluginsNow(plugin -> newIds.add(plugin.getId())); + + var original = newIds.toArray(String.class); + var toCompare = originalIds.toArray(String.class); + + if (!Arrays.equals(original, toCompare)) { + ConfirmDialog.ifOk(Messages.PLUGINS_DIALOG_QUESTION, Platform::exit); + } + } + + /** + * Process install a plugin. + */ + @FxThread + private void processAdd() { + + GAnalytics.sendPageView("PluginChooseDialog", null, "/dialog/PluginChooseDialog"); + GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_OPENED, "PluginChooseDialog"); + + var chooser = new FileChooser(); + chooser.setTitle(Messages.PLUGINS_DIALOG_FILE_CHOOSER_TITLE); + chooser.setSelectedExtensionFilter(new ExtensionFilter(Messages.PLUGINS_DIALOG_FILE_CHOOSER_FILTER, "*.zip")); + chooser.setInitialDirectory(new File(System.getProperty("user.home"))); + + var result = chooser.showOpenDialog(getDialog()); + + if (result == null) { + return; + } + + PLUGIN_MANAGER.installPlugin(result.toPath()); + + refreshPlugins(); + } + + @Override + @FromAnyThread + protected boolean needOkButton() { + return false; + } + + @Override + @FromAnyThread + protected @NotNull String getButtonCloseText() { + return Messages.SIMPLE_DIALOG_BUTTON_CLOSE; + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } +} diff --git a/src/main/java/com/ss/builder/fx/dialog/save/SaveAsEditorDialog.java b/src/main/java/com/ss/builder/fx/dialog/save/SaveAsEditorDialog.java new file mode 100644 index 00000000..77b4d1ed --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/save/SaveAsEditorDialog.java @@ -0,0 +1,443 @@ +package com.ss.builder.fx.dialog.save; + +import static com.ss.builder.Messages.SAVE_AS_EDITOR_DIALOG_FIELD_FILENAME; +import static com.ss.builder.Messages.SAVE_AS_EDITOR_DIALOG_TITLE; +import static com.ss.builder.fx.component.asset.tree.resource.ResourceElementFactory.createFor; +import static com.ss.builder.fx.util.UiUtils.findItemForValue; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.component.asset.tree.ResourceTree; +import com.ss.builder.fx.component.asset.tree.resource.ResourceElement; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.dialog.EditorDialog; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.CreatedFileEvent; +import com.ss.builder.fx.event.impl.DeletedFileEvent; +import com.ss.builder.fx.event.impl.RequestSelectFileEvent; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.event.EventHandler; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.control.TreeItem; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * The implementation of the {@link EditorDialog} to choose how to save an object. + * + * @author JavaSaBr + */ +public class SaveAsEditorDialog extends AbstractSimpleEditorDialog { + + protected static final Point DIALOG_SIZE = new Point(900, -1); + + @NotNull + private final EventHandler createdFileHandler = this::processEvent; + + @NotNull + private final EventHandler selectFileHandle = this::processEvent; + + @NotNull + private final EventHandler deletedFileHandler = this::processEvent; + + /** + * The list of waited files to select. + */ + @NotNull + private final Array waitedFilesToSelect; + + /** + * The function for handling the choose. + */ + @NotNull + protected final Consumer consumer; + + /** + * The tree with all resources. + */ + @NotNull + private ResourceTree resourceTree; + + /** + * The filename field. + */ + @NotNull + private TextField fileNameField; + + /** + * The file extension. + */ + @Nullable + private String extension; + + public SaveAsEditorDialog(@NotNull Consumer consumer) { + this.waitedFilesToSelect = Array.ofType(Path.class); + this.consumer = consumer; + this.resourceTree = new ResourceTree(null, true); + this.fileNameField = new TextField(); + } + + /** + * Get the title of filename field. + * + * @return the title of filename field. + */ + @FxThread + protected @NotNull String getFileNameLabelText() { + return SAVE_AS_EDITOR_DIALOG_FIELD_FILENAME; + } + + /** + * Set the target file extension. + * + * @param extension the target file extension. + */ + @FxThread + public void setExtension(@NotNull String extension) { + this.extension = extension; + getResourceTree().setExtensionFilter(ArrayFactory.asArray(extension)); + } + + /** + * Get the target file extension. + * + * @return the target file extension. + */ + @FxThread + private @NotNull String getExtension() { + return extension == null ? "" : extension; + } + + /** + * Sets action tester. + * + * @param actionTester the action tester. + */ + @FxThread + public void setActionTester(@NotNull Predicate> actionTester) { + getResourceTree().setActionTester(actionTester); + } + + @Override + @FxThread + protected void createContent(@NotNull VBox root) { + super.createContent(root); + + var container = new HBox(); + container.prefWidthProperty() + .bind(widthProperty()); + + var settingsContainer = new GridPane(); + settingsContainer.prefWidthProperty() + .bind(container.widthProperty().multiply(0.5)); + + settingsContainer.prefHeightProperty() + .bind(container.heightProperty()); + + resourceTree.prefWidthProperty() + .bind(container.widthProperty().multiply(0.5)); + + FxControlUtils.onSelectedItemChange(resourceTree, this::processSelection); + + createSettings(settingsContainer); + + FxUtils.addClass(root, CssClasses.SAVE_AS_DIALOG) + .addClass(container, CssClasses.DEF_HBOX) + .addClass(settingsContainer, CssClasses.DEF_GRID_PANE); + + FxUtils.addChild(container, resourceTree, settingsContainer) + .addChild(root, container); + } + + /** + * Create settings of the creating file. + * + * @param root the root + */ + @FxThread + protected void createSettings(@NotNull GridPane root) { + + var fileNameLabel = new Label(getFileNameLabelText() + ":"); + fileNameLabel.prefWidthProperty() + .bind(root.widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); + + fileNameField.prefWidthProperty() + .bind(root.widthProperty()); + + fileNameField.prefWidthProperty() + .bind(root.widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onTextChange(fileNameField, this::validateFileName); + + root.add(fileNameLabel, 0, 0); + root.add(fileNameField, 1, 0); + + FxUtils.addClass(fileNameLabel, CssClasses.DIALOG_DYNAMIC_LABEL) + .addClass(fileNameField, CssClasses.DIALOG_FIELD); + } + + /** + * Handle the new selected item. + * + * @param newValue the new selected item. + */ + @FxThread + protected void processSelection(@Nullable TreeItem newValue) { + + if (newValue != null) { + + var file = newValue.getValue() + .getFile(); + + if (!Files.isDirectory(file)) { + getFileNameField().setText(FileUtils.getNameWithoutExtension(file)); + } + } + + validateFileName(); + } + + /** + * Validate the inputted name. + */ + @FxThread + protected void validateFileName() { + + var okButton = getOkButton(); + if (okButton == null) { + return; + } + + var fileToCreate = getFileToSave(); + + if (fileToCreate == null) { + okButton.setDisable(true); + return; + } + + okButton.setDisable(false); + } + + /** + * Get the file to create. + * + * @return the file to creating. + */ + @FromAnyThread + protected @Nullable Path getFileToSave() { + + var filename = getFileNameField().getText(); + var selectedFile = getSelectedFile(); + + if (StringUtils.isEmpty(filename) || selectedFile == null) { + return null; + } + + var fileExtension = getExtension(); + var directory = Files.isDirectory(selectedFile) ? + selectedFile : selectedFile.getParent(); + + return StringUtils.isEmpty(fileExtension) ? directory.resolve(filename) : + directory.resolve(filename + "." + fileExtension); + } + + /** + * Get the selected file in the resources tree. + * + * @return the selected file in the resources tree. + */ + @FromAnyThread + private @Nullable Path getSelectedFile() { + + var selectedItem = getResourceTree() + .getSelectionModel() + .getSelectedItem(); + + if (selectedItem == null) { + return null; + } + + return selectedItem.getValue() + .getFile(); + } + + /** + * Get the filename field. + * + * @return the filename field. + */ + @FxThread + protected @NotNull TextField getFileNameField() { + return notNull(fileNameField); + } + + @Override + @FxThread + public void show(@NotNull Window owner) { + super.show(owner); + + var currentAsset = EditorConfig.getInstance() + .requiredCurrentAsset(); + + getResourceTree() + .setOnLoadHandler(finished -> expand(currentAsset, finished)) + .fill(currentAsset); + + FxEventManager.getInstance() + .addEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler) + .addEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle) + .addEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); + + validateFileName(); + + ExecutorManager.getInstance() + .addFxTask(getFileNameField()::requestFocus); + } + + @FxThread + private void expand(@NotNull Path file, @NotNull Boolean finished) { + if (finished) { + getResourceTree().expandTo(file, true); + } + } + + /** + * Handle creating file event. + */ + @FxThread + private void processEvent(@NotNull CreatedFileEvent event) { + + var file = event.getFile(); + + var waitedFilesToSelect = getWaitedFilesToSelect(); + var waitedSelect = waitedFilesToSelect.contains(file); + + var resourceTree = getResourceTree(); + resourceTree.notifyCreated(file); + + if (waitedSelect) { + waitedFilesToSelect.fastRemove(file); + } + + if (waitedSelect || event.isNeedSelect()) { + resourceTree.expandTo(file, true); + } + } + + /** + * Handle deleting file event. + */ + @FxThread + private void processEvent(@NotNull final DeletedFileEvent event) { + + final Path file = event.getFile(); + + final ResourceTree resourceTree = getResourceTree(); + resourceTree.notifyDeleted(file); + } + + /** + * Handle selecting file event. + */ + @FxThread + private void processEvent(@NotNull final RequestSelectFileEvent event) { + + final Path file = event.getFile(); + + final ResourceTree resourceTree = getResourceTree(); + final ResourceElement element = createFor(file); + final TreeItem treeItem = findItemForValue(resourceTree.getRoot(), element); + + if (treeItem == null) { + getWaitedFilesToSelect().add(file); + return; + } + + resourceTree.expandTo(treeItem, true); + } + + /** + * @return the list of waited files to select. + */ + @FxThread + private @NotNull Array getWaitedFilesToSelect() { + return waitedFilesToSelect; + } + + @Override + @FxThread + public void hide() { + + FxEventManager.getInstance() + .removeEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler) + .removeEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle) + .removeEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); + + super.hide(); + } + + /** + * Get the function for handling the choose. + * + * @return the function for handling the choose. + */ + @FxThread + protected @NotNull Consumer<@NotNull Path> getConsumer() { + return consumer; + } + + /** + * Get the tree with all resources. + * + * @return the tree with all resources. + */ + @FxThread + private @NotNull ResourceTree getResourceTree() { + return notNull(resourceTree); + } + + @Override + @FromAnyThread + protected @NotNull String getTitleText() { + return SAVE_AS_EDITOR_DIALOG_TITLE; + } + + @Override + @FromAnyThread + protected @NotNull Point getSize() { + return DIALOG_SIZE; + } + + @Override + @FromAnyThread + protected @NotNull String getButtonOkText() { + return Messages.SIMPLE_DIALOG_BUTTON_SAVE; + } + + @Override + @FxThread + protected void processOk() { + super.processOk(); + consumer.accept(notNull(getFileToSave())); + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/scene/selector/FilterSceneSelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/scene/selector/FilterSceneSelectorDialog.java similarity index 91% rename from src/main/java/com/ss/editor/ui/dialog/scene/selector/FilterSceneSelectorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/scene/selector/FilterSceneSelectorDialog.java index 24a27e76..2335bbb0 100644 --- a/src/main/java/com/ss/editor/ui/dialog/scene/selector/FilterSceneSelectorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/scene/selector/FilterSceneSelectorDialog.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.dialog.scene.selector; +package com.ss.builder.fx.dialog.scene.selector; import com.jme3.post.Filter; import com.ss.editor.extension.scene.SceneNode; diff --git a/src/main/java/com/ss/editor/ui/dialog/scene/selector/SceneSelectorDialog.java b/src/main/java/com/ss/builder/fx/dialog/scene/selector/SceneSelectorDialog.java similarity index 84% rename from src/main/java/com/ss/editor/ui/dialog/scene/selector/SceneSelectorDialog.java rename to src/main/java/com/ss/builder/fx/dialog/scene/selector/SceneSelectorDialog.java index c5bdfae4..7546c2dd 100644 --- a/src/main/java/com/ss/editor/ui/dialog/scene/selector/SceneSelectorDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/scene/selector/SceneSelectorDialog.java @@ -1,15 +1,22 @@ -package com.ss.editor.ui.dialog.scene.selector; +package com.ss.builder.fx.dialog.scene.selector; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.ui.control.scene.SceneNodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.control.scene.SceneNodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; diff --git a/src/main/java/com/ss/builder/fx/dialog/sky/CreateEditableSkyDialog.java b/src/main/java/com/ss/builder/fx/dialog/sky/CreateEditableSkyDialog.java new file mode 100644 index 00000000..49ed0258 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/dialog/sky/CreateEditableSkyDialog.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.dialog.sky; + +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import org.jetbrains.annotations.NotNull; + +/** + * The dialog to create sky using SS Sky Factory. + * + * @author JavaSaBr + */ +public class CreateEditableSkyDialog extends CreateSkyDialog { + + public CreateEditableSkyDialog(@NotNull final TreeNode parentNode, + @NotNull final NodeTree nodeTree) { + super(parentNode, nodeTree); + } + + @Override + protected boolean isEditableSky() { + return true; + } +} diff --git a/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java b/src/main/java/com/ss/builder/fx/dialog/sky/CreateSkyDialog.java similarity index 95% rename from src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java rename to src/main/java/com/ss/builder/fx/dialog/sky/CreateSkyDialog.java index 3bb91a60..a270fa91 100644 --- a/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/sky/CreateSkyDialog.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.dialog.sky; +package com.ss.builder.fx.dialog.sky; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.builder.util.EditorUtils.toAssetPath; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.nio.file.StandardOpenOption.*; import static javafx.collections.FXCollections.observableArrayList; @@ -14,25 +14,25 @@ import com.jme3.texture.Texture; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.FileExtensions; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.util.JmbSkyFactory; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.choose.ChooseFolderControl; -import com.ss.editor.ui.control.choose.ChooseTextureControl; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.MaterialSerializer; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.control.choose.ChooseFolderControl; +import com.ss.builder.fx.control.choose.ChooseTextureControl; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.MaterialSerializer; import com.ss.rlib.fx.control.input.FloatTextField; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.StringUtils; @@ -608,7 +608,11 @@ private void processChange(@NotNull final SkyType newValue) { */ @FxThread private void validate() { - if (!isReady()) return; + + //FIXME + /*if (!isReady()) { + return; + }*/ final ComboBox skyTypeComboBox = getSkyTypeComboBox(); final SingleSelectionModel selectionModel = skyTypeComboBox.getSelectionModel(); @@ -743,7 +747,7 @@ protected void processOk() { try { createSkyInBackground(); } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); } EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); @@ -758,7 +762,7 @@ protected void processOk() { @FxThread private void createSkyInBackground() { - final AssetManager assetManager = EditorUtil.getAssetManager(); + final AssetManager assetManager = EditorUtils.getAssetManager(); final NodeTree nodeTree = getNodeTree(); final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); @@ -897,9 +901,9 @@ private void createSingleTexture(@NotNull final AssetManager assetManager, throw new RuntimeException(e); } - final Path assetFile = EditorUtil.getAssetFile(materialFile); - final String assetPath = EditorUtil.toAssetPath(assetFile); - final AssetManager assetManager = EditorUtil.getAssetManager(); + final Path assetFile = EditorUtils.getAssetFile(materialFile); + final String assetPath = EditorUtils.toAssetPath(assetFile); + final AssetManager assetManager = EditorUtils.getAssetManager(); return assetManager.loadMaterial(assetPath); } diff --git a/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java b/src/main/java/com/ss/builder/fx/dialog/terrain/CreateTerrainDialog.java similarity index 94% rename from src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java rename to src/main/java/com/ss/builder/fx/dialog/terrain/CreateTerrainDialog.java index 881d6ec1..c5ce34dc 100644 --- a/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java +++ b/src/main/java/com/ss/builder/fx/dialog/terrain/CreateTerrainDialog.java @@ -1,8 +1,5 @@ -package com.ss.editor.ui.dialog.terrain; +package com.ss.builder.fx.dialog.terrain; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static javafx.collections.FXCollections.observableArrayList; import com.jme3.asset.AssetManager; @@ -18,25 +15,26 @@ import com.jme3.terrain.heightmap.HillHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; import com.jme3.texture.Texture; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.choose.ChooseFolderControl; -import com.ss.editor.ui.control.choose.ChooseTextureControl; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.Messages; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.control.choose.ChooseFolderControl; +import com.ss.builder.fx.control.choose.ChooseTextureControl; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.fx.control.input.FloatTextField; import com.ss.rlib.fx.control.input.IntegerTextField; import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.FileUtils; import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.control.Button; @@ -357,7 +355,7 @@ protected void createContent(@NotNull final VBox root) { heightMapScaleField = new FloatTextField(); heightMapScaleField.prefWidthProperty().bind(baseTextureControl.widthProperty()); - heightMapScaleField.setValue(1); + heightMapScaleField.setValue(1F); heightMapSettings = new GridPane(); heightMapSettings.add(heightMapImageControlLabel, 0, 0); @@ -388,8 +386,8 @@ protected void createContent(@NotNull final VBox root) { hillMinRadiusField = new FloatTextField(); hillMinRadiusField.prefWidthProperty().bind(baseTextureControl.widthProperty()); - hillMinRadiusField.setMinMax(0, 1000); - hillMinRadiusField.setValue(20); + hillMinRadiusField.setMinMax(0F, 1000F); + hillMinRadiusField.setValue(20F); hillMinRadiusField.addChangeListener((observable, oldValue, newValue) -> validate()); final Label hillMaxRadiusLabel = new Label(Messages.CREATE_TERRAIN_DIALOG_MAX_RADIUS + ":"); @@ -397,8 +395,8 @@ protected void createContent(@NotNull final VBox root) { hillMaxRadiusField = new FloatTextField(); hillMaxRadiusField.prefWidthProperty().bind(baseTextureControl.widthProperty()); - hillMaxRadiusField.setMinMax(0, 1000); - hillMaxRadiusField.setValue(50); + hillMaxRadiusField.setMinMax(0F, 1000F); + hillMaxRadiusField.setValue(50F); hillMaxRadiusField.addChangeListener((observable, oldValue, newValue) -> validate()); hillSettings = new GridPane(); @@ -671,7 +669,7 @@ protected void processOk() { try { createTerrainInBackground(); } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); } EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); @@ -684,7 +682,7 @@ protected void processOk() { @BackgroundThread private void createTerrainInBackground() throws Exception { - final AssetManager assetManager = EditorUtil.getAssetManager(); + final AssetManager assetManager = EditorUtils.getAssetManager(); final ComboBox heightMapTypeComboBox = getHeightMapTypeComboBox(); final HeightMapType heightMapType = heightMapTypeComboBox.getSelectionModel().getSelectedItem(); @@ -713,8 +711,8 @@ private void createTerrainInBackground() throws Exception { case IMAGE_BASED: { final Path heightMapTextureFile = notNull(heightMapImageControl.getTextureFile()); - final Path assetFile = notNull(getAssetFile(heightMapTextureFile)); - final Texture texture = assetManager.loadTexture(toAssetPath(assetFile)); + final Path assetFile = notNull(EditorUtils.getAssetFile(heightMapTextureFile)); + final Texture texture = assetManager.loadTexture(EditorUtils.toAssetPath(assetFile)); heightmap = new ImageBasedHeightMap(texture.getImage(), heightMapScaleField.getValue()); break; @@ -771,8 +769,8 @@ private void createTerrainInBackground() throws Exception { ImageIO.write(alphaBlend, "png", textureFile.toFile()); - final Path assetFile = notNull(getAssetFile(textureFile)); - final Texture texture = assetManager.loadAsset(new TextureKey(toAssetPath(assetFile), false)); + final Path assetFile = notNull(EditorUtils.getAssetFile(textureFile)); + final Texture texture = assetManager.loadAsset(new TextureKey(EditorUtils.toAssetPath(assetFile), false)); switch (i) { case 0: { @@ -798,7 +796,7 @@ private void createTerrainInBackground() throws Exception { final Path baseTextureFile = notNull(baseTextureControl.getTextureFile()); // give the first layer default texture - final Texture baseTexture = assetManager.loadTexture(toAssetPath(notNull(getAssetFile(baseTextureFile)))); + final Texture baseTexture = assetManager.loadTexture(EditorUtils.toAssetPath(notNull(EditorUtils.getAssetFile(baseTextureFile)))); baseTexture.setWrap(Texture.WrapMode.Repeat); terrainMaterial.setTexture("DiffuseMap", baseTexture); @@ -807,7 +805,7 @@ private void createTerrainInBackground() throws Exception { terrainMaterial.setBoolean("WardIso", true); final com.jme3.scene.Node terrainNode = (com.jme3.scene.Node) terrain; - terrainNode.setUserData(KEY_LOADED_MODEL, true); + terrainNode.setUserData(AbstractSceneEditor3dPart.KEY_LOADED_MODEL, true); terrainNode.setMaterial(terrainMaterial); terrainNode.setModelBound(new BoundingBox()); terrainNode.updateModelBound(); diff --git a/src/main/java/com/ss/builder/fx/editor/layout/EditorLayout.java b/src/main/java/com/ss/builder/fx/editor/layout/EditorLayout.java new file mode 100644 index 00000000..a408d5e2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/layout/EditorLayout.java @@ -0,0 +1,19 @@ +package com.ss.builder.fx.editor.layout; + +import com.ss.builder.annotation.FromAnyThread; +import javafx.scene.Parent; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement layout container of Editor. + * + * @author JavaSaBr + */ +public interface EditorLayout { + + @FromAnyThread + @NotNull Parent getRootPage(); + + @FromAnyThread + @NotNull Parent getContainer(); +} diff --git a/src/main/java/com/ss/builder/fx/editor/layout/impl/AbstractEditorLayout.java b/src/main/java/com/ss/builder/fx/editor/layout/impl/AbstractEditorLayout.java new file mode 100644 index 00000000..d1055575 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/layout/impl/AbstractEditorLayout.java @@ -0,0 +1,53 @@ +package com.ss.builder.fx.editor.layout.impl; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.editor.layout.EditorLayout; +import javafx.scene.Parent; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of the {@link EditorLayout} + * + * @author JavaSaBr + */ +public abstract class AbstractEditorLayout implements EditorLayout { + + /** + * The root page. + */ + @NotNull + protected final R rootPage; + + /** + * The container. + */ + @NotNull + protected final C container; + + protected AbstractEditorLayout() { + this.rootPage = createRootPage(); + this.container = createContainer(); + } + + @FromAnyThread + public void build() { + } + + @FromAnyThread + protected abstract @NotNull C createContainer(); + + @FromAnyThread + protected abstract @NotNull R createRootPage(); + + @Override + @FromAnyThread + public @NotNull Parent getRootPage() { + return rootPage; + } + + @Override + @FromAnyThread + public @NotNull Parent getContainer() { + return container; + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/layout/impl/PaneEditorLayout.java b/src/main/java/com/ss/builder/fx/editor/layout/impl/PaneEditorLayout.java new file mode 100644 index 00000000..6b882e6a --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/layout/impl/PaneEditorLayout.java @@ -0,0 +1,17 @@ +package com.ss.builder.fx.editor.layout.impl; + +import com.ss.builder.fx.editor.layout.EditorLayout; +import javafx.scene.Parent; +import org.jetbrains.annotations.NotNull; + +public class PaneEditorLayout implements EditorLayout { + @Override + public @NotNull Parent getRootPage() { + return null; + } + + @Override + public @NotNull Parent getContainer() { + return null; + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/layout/impl/VBoxEditorLayout.java b/src/main/java/com/ss/builder/fx/editor/layout/impl/VBoxEditorLayout.java new file mode 100644 index 00000000..a0ca8051 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/layout/impl/VBoxEditorLayout.java @@ -0,0 +1,35 @@ +package com.ss.builder.fx.editor.layout.impl; + +import com.ss.builder.annotation.FromAnyThread; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; + +/** + * The simple editor layout. + * + * @author JavaSaBr + */ +public class VBoxEditorLayout extends AbstractEditorLayout { + + public VBoxEditorLayout() { + } + + @Override + @FromAnyThread + public void build() { + super.build(); + } + + @Override + @FromAnyThread + protected @NotNull VBox createContainer() { + return rootPage; + } + + + @Override + @FromAnyThread + protected @NotNull VBox createRootPage() { + return new VBox(); + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/part/ui/AbstractEditorUiPart.java b/src/main/java/com/ss/builder/fx/editor/part/ui/AbstractEditorUiPart.java new file mode 100644 index 00000000..31e1fc81 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/part/ui/AbstractEditorUiPart.java @@ -0,0 +1,22 @@ +package com.ss.builder.fx.editor.part.ui; + +import com.ss.builder.editor.FileEditor; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of Ui part. + * + * @author JavaSaBr + */ +public abstract class AbstractEditorUiPart implements EditorUiPart { + + /** + * The file editor. + */ + @NotNull + protected final T fileEditor; + + protected AbstractEditorUiPart(@NotNull T fileEditor) { + this.fileEditor = fileEditor; + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/part/ui/AudioViewerUiPart.java b/src/main/java/com/ss/builder/fx/editor/part/ui/AudioViewerUiPart.java new file mode 100644 index 00000000..103085a0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/part/ui/AudioViewerUiPart.java @@ -0,0 +1,127 @@ +package com.ss.builder.fx.editor.part.ui; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.impl.audio.AudioViewerEditor; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.editor.layout.EditorLayout; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.image.ImageView; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of Ui part of {@link AudioViewerEditor}. + * + * @author JavaSaBr + */ +public class AudioViewerUiPart extends AbstractEditorUiPart { + + /** + * The play button. + */ + @NotNull + private final Button playButton; + + /** + * The stop button. + */ + @NotNull + private final Button stopButton; + + /** + * The duration field. + */ + @NotNull + private final TextField durationField; + + /** + * The bits per sample field. + */ + @NotNull + private final TextField bitsPerSampleField; + + /** + * The channels field. + */ + @NotNull + private final TextField channelsField; + + /** + * The data type field. + */ + @NotNull + private final TextField dataTypeField; + + /** + * The sample rate field. + */ + @NotNull + private final TextField sampleRateField; + + public AudioViewerUiPart(@NotNull AudioViewerEditor fileEditor) { + super(fileEditor); + this.bitsPerSampleField = new TextField(); + this.channelsField = new TextField(); + this.durationField = new TextField(); + this.dataTypeField = new TextField(); + this.sampleRateField = new TextField(); + this.playButton = new Button(); + this.stopButton = new Button(); + } + + @FxThread + @Override + public void buildUi(@NotNull EditorLayout layout) { + + var durationLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_DURATION_LABEL + ":"); + var bitsPerSampleLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_BITS_PER_SAMPLE_LABEL + ":"); + var channelsLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_CHANNELS_LABEL + ":"); + var dataTypeLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_DATA_TYPE_LABEL + ":"); + var sampleRateLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_SAMPLE_RATE_LABEL + ":"); + + durationField.setEditable(false); + bitsPerSampleField.setEditable(false); + channelsField.setEditable(false); + dataTypeField.setEditable(false); + sampleRateField.setEditable(false); + + var gridPane = new GridPane(); + gridPane.add(durationLabel, 0, 0); + gridPane.add(bitsPerSampleLabel, 0, 1); + gridPane.add(channelsLabel, 0, 2); + gridPane.add(dataTypeLabel, 0, 3); + gridPane.add(sampleRateLabel, 0, 4); + gridPane.add(durationField, 1, 0); + gridPane.add(bitsPerSampleField, 1, 1); + gridPane.add(channelsField, 1, 2); + gridPane.add(dataTypeField, 1, 3); + gridPane.add(sampleRateField, 1, 4); + + playButton.setGraphic(new ImageView(Icons.PLAY_128)); + playButton.setOnAction(event -> fileEditor.processPlay()); + + stopButton.setGraphic(new ImageView(Icons.STOP_128)); + stopButton.setOnAction(event -> processStop()); + stopButton.setDisable(true); + + var container = new HBox(); + + FxUtils.addClass(playButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER) + .addClass(stopButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER) + .addClass(container, CssClasses.DEF_HBOX) + .addClass(gridPane, CssClasses.DEF_GRID_PANE) + .addClass(root, CssClasses.DEF_VBOX, CssClasses.AUDIO_VIEW_EDITOR_CONTAINER); + + FxUtils.addChild(container, gridPane, playButton, stopButton) + .addChild(root, container); + + DynamicIconSupport.addSupport(playButton, stopButton); + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/part/ui/EditorUiPart.java b/src/main/java/com/ss/builder/fx/editor/part/ui/EditorUiPart.java new file mode 100644 index 00000000..1dacd8aa --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/part/ui/EditorUiPart.java @@ -0,0 +1,22 @@ +package com.ss.builder.fx.editor.part.ui; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.editor.layout.EditorLayout; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement a Ui part of editor. + * + * @author JavaSaBr + */ +public interface EditorUiPart { + + /** + * Build Ui controls on the editor's layout. + * + * @param layout the editor's layout. + */ + @FxThread + default void buildUi(@NotNull EditorLayout layout) { + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/toolbar/SaveToolbarAction.java b/src/main/java/com/ss/builder/fx/editor/toolbar/SaveToolbarAction.java new file mode 100644 index 00000000..5ca5be1d --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/toolbar/SaveToolbarAction.java @@ -0,0 +1,42 @@ +package com.ss.builder.fx.editor.toolbar; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.fx.Icons; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * The action to save an opened file in an editor. + * + * @author JavaSaBr + */ +public class SaveToolbarAction extends ToolbarAction { + + public SaveToolbarAction(@NotNull FileEditor fileEditor) { + super(fileEditor); + disableProperty().bind(fileEditor.dirtyProperty().not()); + } + + @Override + @FromAnyThread + protected @NotNull Optional getToolTipText() { + return Optional.of(Messages.FILE_EDITOR_ACTION_SAVE + " (Ctrl + S)"); + } + + @Override + @FromAnyThread + protected @NotNull Image getIcon() { + return Icons.SAVE_16; + } + + @Override + @FxThread + protected void activate() { + fileEditor.save(); + } +} diff --git a/src/main/java/com/ss/builder/fx/editor/toolbar/ToolbarAction.java b/src/main/java/com/ss/builder/fx/editor/toolbar/ToolbarAction.java new file mode 100644 index 00000000..c16eab73 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/editor/toolbar/ToolbarAction.java @@ -0,0 +1,66 @@ +package com.ss.builder.fx.editor.toolbar; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Tooltip; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * The base toolbar action for {@link FileEditor}. + * + * @author JavaSaBr + */ +public abstract class ToolbarAction extends Button { + + /** + * The file editor. + */ + @NotNull + protected final T fileEditor; + + public ToolbarAction(@NotNull T fileEditor) { + this.fileEditor = fileEditor; + + setGraphic(new ImageView(getIcon())); + setOnAction(event -> activate()); + getToolTipText().ifPresent(text -> setTooltip(new Tooltip(text))); + + FxUtils.addClass(this, + CssClasses.FLAT_BUTTON, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + + DynamicIconSupport.addSupport(this); + } + + /** + * Get the action's icon. + * + * @return the action's icon. + */ + @FromAnyThread + protected abstract @NotNull Image getIcon(); + + /** + * Get the tooltip text for this action. + * + * @return the tooltip text for this action. + */ + @FromAnyThread + protected @NotNull Optional getToolTipText() { + return Optional.empty(); + } + + /** + * Activate this action. + */ + @FxThread + protected abstract void activate(); +} diff --git a/src/main/java/com/ss/editor/ui/event/ConsumableEvent.java b/src/main/java/com/ss/builder/fx/event/ConsumableEvent.java similarity index 86% rename from src/main/java/com/ss/editor/ui/event/ConsumableEvent.java rename to src/main/java/com/ss/builder/fx/event/ConsumableEvent.java index 0495772a..3b8e0d49 100644 --- a/src/main/java/com/ss/editor/ui/event/ConsumableEvent.java +++ b/src/main/java/com/ss/builder/fx/event/ConsumableEvent.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.event; +package com.ss.builder.fx.event; /** * The interface marker. diff --git a/src/main/java/com/ss/editor/ui/event/EventRedirector.java b/src/main/java/com/ss/builder/fx/event/EventRedirector.java similarity index 96% rename from src/main/java/com/ss/editor/ui/event/EventRedirector.java rename to src/main/java/com/ss/builder/fx/event/EventRedirector.java index c88124d6..bd3bf751 100644 --- a/src/main/java/com/ss/editor/ui/event/EventRedirector.java +++ b/src/main/java/com/ss/builder/fx/event/EventRedirector.java @@ -1,10 +1,10 @@ -package com.ss.editor.ui.event; +package com.ss.builder.fx.event; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.config.Config; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.editor.ui.component.editor.area.EditorAreaComponent; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.config.Config; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.fx.component.EditorAreaComponent; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import javafx.event.Event; diff --git a/src/main/java/com/ss/builder/fx/event/FxEventManager.java b/src/main/java/com/ss/builder/fx/event/FxEventManager.java new file mode 100644 index 00000000..199ceafa --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/FxEventManager.java @@ -0,0 +1,138 @@ +package com.ss.builder.fx.event; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.application.Platform; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.event.EventType; +import org.jetbrains.annotations.NotNull; + +/** + * The class to manage javaFX events. + * + * @author JavaSaBr + */ +public class FxEventManager { + + private static final FxEventManager INSTANCE = new FxEventManager(); + + @FromAnyThread + public static @NotNull FxEventManager getInstance() { + return INSTANCE; + } + + /** + * The table of event handlers. + */ + @NotNull + private final ObjectDictionary, + Array>> eventHandlers; + + public FxEventManager() { + InitializeManager.valid(getClass()); + this.eventHandlers = DictionaryFactory.newObjectDictionary(); + } + + /** + * Add a new event handler. + * + * @param eventType the event type. + * @param eventHandler the event handler. + */ + @FxThread + public @NotNull FxEventManager addEventHandler( + @NotNull EventType eventType, + @NotNull EventHandler eventHandler + ) { + + if (!Platform.isFxApplicationThread()) { + + ExecutorManager.getInstance() + .addFxTask(() -> addEventHandler(eventType, eventHandler)); + + return this; + } + + getEventHandlers().get(eventType, Array.supplier(EventHandler.class)) + .add(eventHandler); + + return this; + } + + /** + * Remove an old event handler. + * + * @param eventType the event type. + * @param eventHandler the event handler. + */ + @FxThread + public @NotNull FxEventManager removeEventHandler( + @NotNull EventType eventType, + @NotNull EventHandler eventHandler + ) { + + getEventHandlers().getOptional(eventType) + .ifPresent(handlers -> handlers.slowRemove(eventHandler)); + + return this; + } + + /** + * Get the table of event handlers. + * + * @return the table of event handlers. + */ + @FxThread + private @NotNull ObjectDictionary, + Array>> getEventHandlers() { + return eventHandlers; + } + + /** + * Notify about a new event. + * + * @param event the new event. + */ + @FromAnyThread + public void notify(@NotNull Event event) { + if (Platform.isFxApplicationThread()) { + notifyImpl(event); + } else { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> notifyImpl(event)); + } + } + + /** + * The process of handling a new event. + */ + @FxThread + private void notifyImpl(@NotNull Event event) { + + var eventHandlers = getEventHandlers(); + + for (EventType eventType = event.getEventType(); eventType != null; + eventType = eventType.getSuperType()) { + + var handlers = eventHandlers.get(eventType); + if (handlers == null || handlers.isEmpty()) { + continue; + } + + handlers.forEach(event, (handler, toHandle) -> + handler.handle(ClassUtils.unsafeCast(event))); + } + + if (event instanceof ConsumableEvent && !event.isConsumed()) { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> notifyImpl(event)); + } + } +} diff --git a/src/main/java/com/ss/builder/fx/event/SceneEvent.java b/src/main/java/com/ss/builder/fx/event/SceneEvent.java new file mode 100644 index 00000000..8497bffe --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/SceneEvent.java @@ -0,0 +1,97 @@ +package com.ss.builder.fx.event; + +import com.ss.builder.annotation.FxThread; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.event.Event; +import javafx.event.EventType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The base implementation of an event in the javaFX UI. + * + * @author JavaSaBr + */ +public class SceneEvent extends Event { + + private static final long serialVersionUID = 6827900349094865635L; + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.class.getSimpleName()); + } + } + + /** + * The parameters. + */ + @Nullable + private ObjectDictionary values; + + public SceneEvent(@Nullable Object source, @NotNull EventType eventType) { + super(source, null, eventType); + } + + public SceneEvent(@NotNull EventType eventType) { + super(eventType); + } + + /** + * Get the map of all values of this event. + * + * @return the map of all values of this event. + */ + @FxThread + private @NotNull Optional> getValues() { + return Optional.ofNullable(values); + } + + /** + * Put the new parameter. + * + * @param key the key. + * @param value the value. + */ + public void set(@NotNull Object key, @NotNull Object value) { + + if (values == null) { + values = DictionaryFactory.newObjectDictionary(); + } + + values.put(key, value); + } + + /** + * Remove a value by the key. + * + * @param key the key. + */ + public void remove(@NotNull Object key) { + getValues().ifPresent(objects -> objects.remove(key)); + } + + /** + * Get a value by the key. + * + * @param the result's type. + * @param key the key. + * @return the value or null. + */ + public @Nullable T get(@NotNull Object key) { + return getValues() + .map(objects -> objects.get(key)) + .map(ClassUtils::unsafeCast) + .orElse(null); + } + + @Override + public String toString() { + return eventType.toString(); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/AllPluginsExtensionsRegisteredEvent.java b/src/main/java/com/ss/builder/fx/event/impl/AllPluginsExtensionsRegisteredEvent.java new file mode 100644 index 00000000..8651ab25 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/AllPluginsExtensionsRegisteredEvent.java @@ -0,0 +1,25 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that all plugins have registered all their + * extensions. + * + * @author JavaSaBr + */ +public class AllPluginsExtensionsRegisteredEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, AllPluginsExtensionsRegisteredEvent.class.getSimpleName()); + } + } + + public AllPluginsExtensionsRegisteredEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/AssetComponentLoadedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/AssetComponentLoadedEvent.java similarity index 93% rename from src/main/java/com/ss/editor/ui/event/impl/AssetComponentLoadedEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/AssetComponentLoadedEvent.java index 1642f483..9f592f2a 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/AssetComponentLoadedEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/AssetComponentLoadedEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/event/impl/ChangedCurrentAssetFolderEvent.java b/src/main/java/com/ss/builder/fx/event/impl/ChangedCurrentAssetFolderEvent.java similarity index 75% rename from src/main/java/com/ss/editor/ui/event/impl/ChangedCurrentAssetFolderEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/ChangedCurrentAssetFolderEvent.java index 559d298d..fb39f0f1 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/ChangedCurrentAssetFolderEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/ChangedCurrentAssetFolderEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; @@ -15,11 +15,7 @@ */ public class ChangedCurrentAssetFolderEvent extends SceneEvent { - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE; + public static final EventType EVENT_TYPE; static { synchronized (Event.class) { @@ -33,7 +29,7 @@ public ChangedCurrentAssetFolderEvent() { super(EVENT_TYPE); } - public ChangedCurrentAssetFolderEvent(@NotNull final Path assetFolder) { + public ChangedCurrentAssetFolderEvent(@NotNull Path assetFolder) { super(EVENT_TYPE); setNewAssetFolder(assetFolder); } @@ -52,7 +48,7 @@ public ChangedCurrentAssetFolderEvent(@NotNull final Path assetFolder) { * * @param newAssetFolder the new asset folder. */ - public void setNewAssetFolder(@NotNull final Path newAssetFolder) { + public void setNewAssetFolder(@NotNull Path newAssetFolder) { set(ASSET, newAssetFolder); } } diff --git a/src/main/java/com/ss/builder/fx/event/impl/ClasspathReloadedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/ClasspathReloadedEvent.java new file mode 100644 index 00000000..c0492d5f --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/ClasspathReloadedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about changed focus of a window. + * + * @author JavaSaBr + */ +public class ClasspathReloadedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, ClasspathReloadedEvent.class.getSimpleName()); + } + } + + public ClasspathReloadedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/CoreClassesScannedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/CoreClassesScannedEvent.java new file mode 100644 index 00000000..a4487afd --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/CoreClassesScannedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that core classes were scanned. + * + * @author JavaSaBr + */ +public class CoreClassesScannedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, CoreClassesScannedEvent.class.getSimpleName()); + } + } + + public CoreClassesScannedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/CreatedFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/CreatedFileEvent.java similarity index 96% rename from src/main/java/com/ss/editor/ui/event/impl/CreatedFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/CreatedFileEvent.java index e3f8eebe..b9d906c1 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/CreatedFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/CreatedFileEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/event/impl/CssAppliedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/CssAppliedEvent.java new file mode 100644 index 00000000..0347801b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/CssAppliedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that css registry applied the current set of CSS files. + * + * @author JavaSaBr + */ +public class CssAppliedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, CssAppliedEvent.class.getSimpleName()); + } + } + + public CssAppliedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/DeletedFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/DeletedFileEvent.java similarity index 94% rename from src/main/java/com/ss/editor/ui/event/impl/DeletedFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/DeletedFileEvent.java index 9a3cf41b..9539d23e 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/DeletedFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/DeletedFileEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/event/impl/EditorFinishedLoadingEvent.java b/src/main/java/com/ss/builder/fx/event/impl/EditorFinishedLoadingEvent.java new file mode 100644 index 00000000..cf517431 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/EditorFinishedLoadingEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that Editor has finished loading. + * + * @author JavaSaBr + */ +public class EditorFinishedLoadingEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, EditorFinishedLoadingEvent.class.getSimpleName()); + } + } + + public EditorFinishedLoadingEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/FileChangedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/FileChangedEvent.java similarity index 92% rename from src/main/java/com/ss/editor/ui/event/impl/FileChangedEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/FileChangedEvent.java index 21c01762..3aa3e239 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/FileChangedEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/FileChangedEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/event/impl/FxContextCreatedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/FxContextCreatedEvent.java new file mode 100644 index 00000000..e3122293 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/FxContextCreatedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that the JavaFX context was created. + * + * @author JavaSaBr + */ +public class FxContextCreatedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, FxContextCreatedEvent.class.getSimpleName()); + } + } + + public FxContextCreatedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/FxSceneAttachedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/FxSceneAttachedEvent.java new file mode 100644 index 00000000..378da4c2 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/FxSceneAttachedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that the JavaFX scene was attached to the main window. + * + * @author JavaSaBr + */ +public class FxSceneAttachedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, FxSceneAttachedEvent.class.getSimpleName()); + } + } + + public FxSceneAttachedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/FxSceneCreatedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/FxSceneCreatedEvent.java new file mode 100644 index 00000000..12cdbc95 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/FxSceneCreatedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that the JavaFX scene was created. + * + * @author JavaSaBr + */ +public class FxSceneCreatedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, FxSceneCreatedEvent.class.getSimpleName()); + } + } + + public FxSceneCreatedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/ImageSystemInitializedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/ImageSystemInitializedEvent.java new file mode 100644 index 00000000..4c534e7b --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/ImageSystemInitializedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that Image System was initialized. + * + * @author JavaSaBr + */ +public class ImageSystemInitializedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, ImageSystemInitializedEvent.class.getSimpleName()); + } + } + + public ImageSystemInitializedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/JmeContextCreatedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/JmeContextCreatedEvent.java new file mode 100644 index 00000000..d7e7ba15 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/JmeContextCreatedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that the jME context was created. + * + * @author JavaSaBr + */ +public class JmeContextCreatedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, JmeContextCreatedEvent.class.getSimpleName()); + } + } + + public JmeContextCreatedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/ManagersInitializedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/ManagersInitializedEvent.java new file mode 100644 index 00000000..466357e0 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/ManagersInitializedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that all managers were initialized. + * + * @author JavaSaBr + */ +public class ManagersInitializedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, ManagersInitializedEvent.class.getSimpleName()); + } + } + + public ManagersInitializedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/MovedFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/MovedFileEvent.java similarity index 82% rename from src/main/java/com/ss/editor/ui/event/impl/MovedFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/MovedFileEvent.java index 7f5b319b..0bc69764 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/MovedFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/MovedFileEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; @@ -15,11 +15,7 @@ */ public class MovedFileEvent extends SceneEvent { - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE; + public static final EventType EVENT_TYPE; static { synchronized (Event.class) { @@ -30,8 +26,10 @@ public class MovedFileEvent extends SceneEvent { private static final String PREV_FILE = "prev_file"; private static final String NEW_FILE = "new_file"; - public MovedFileEvent() { + public MovedFileEvent(@NotNull Path prevFile, @NotNull Path newFile) { super(EVENT_TYPE); + setPrevFile(prevFile); + setNewFile(newFile); } /** diff --git a/src/main/java/com/ss/builder/fx/event/impl/PluginCssLoadedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/PluginCssLoadedEvent.java new file mode 100644 index 00000000..f57aa251 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/PluginCssLoadedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that css registry has loaded plugin's css files. + * + * @author JavaSaBr + */ +public class PluginCssLoadedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, PluginCssLoadedEvent.class.getSimpleName()); + } + } + + public PluginCssLoadedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/PluginsLoadedEvent.java b/src/main/java/com/ss/builder/fx/event/impl/PluginsLoadedEvent.java new file mode 100644 index 00000000..9ffbe341 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/PluginsLoadedEvent.java @@ -0,0 +1,24 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that all plugins were loaded. + * + * @author JavaSaBr + */ +public class PluginsLoadedEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, PluginsLoadedEvent.class.getSimpleName()); + } + } + + public PluginsLoadedEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/PluginsRegisteredResourcesEvent.java b/src/main/java/com/ss/builder/fx/event/impl/PluginsRegisteredResourcesEvent.java new file mode 100644 index 00000000..d63b49c5 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/PluginsRegisteredResourcesEvent.java @@ -0,0 +1,26 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.EventType; + +/** + * The event about that all plugins have already registered all + * interested resources in {@link ResourceManager}. + * + * @author JavaSaBr + */ +public class PluginsRegisteredResourcesEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (EventType.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, PluginsRegisteredResourcesEvent.class.getSimpleName()); + } + } + + public PluginsRegisteredResourcesEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/RenamedFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RenamedFileEvent.java similarity index 76% rename from src/main/java/com/ss/editor/ui/event/impl/RenamedFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/RenamedFileEvent.java index 3866c167..4bd01bea 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/RenamedFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/RenamedFileEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; @@ -15,11 +15,7 @@ */ public class RenamedFileEvent extends SceneEvent { - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE; + public static final EventType EVENT_TYPE; static { synchronized (Event.class) { @@ -30,8 +26,10 @@ public class RenamedFileEvent extends SceneEvent { private static final String PREV_FILE = "prev_file"; private static final String NEW_FILE = "new_file"; - public RenamedFileEvent() { + public RenamedFileEvent(@NotNull Path prevFile, @NotNull Path newFile) { super(EVENT_TYPE); + setPrevFile(prevFile); + setNewFile(newFile); } /** @@ -48,7 +46,7 @@ public RenamedFileEvent() { * * @param file the new file. */ - public void setNewFile(@NotNull final Path file) { + public void setNewFile(@NotNull Path file) { set(NEW_FILE, file); } @@ -66,7 +64,7 @@ public void setNewFile(@NotNull final Path file) { * * @param file the previous file. */ - public void setPrevFile(@NotNull final Path file) { + public void setPrevFile(@NotNull Path file) { set(PREV_FILE, file); } } diff --git a/src/main/java/com/ss/editor/ui/event/impl/RequestSelectFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RequestSelectFileEvent.java similarity index 85% rename from src/main/java/com/ss/editor/ui/event/impl/RequestSelectFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/RequestSelectFileEvent.java index e10d0334..bddc1e68 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/RequestSelectFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/RequestSelectFileEvent.java @@ -1,7 +1,7 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; @@ -24,8 +24,9 @@ public class RequestSelectFileEvent extends SceneEvent { private static final String FILE = "file"; - public RequestSelectFileEvent() { + public RequestSelectFileEvent(@NotNull Path file) { super(EVENT_TYPE); + setFile(file); } /** diff --git a/src/main/java/com/ss/builder/fx/event/impl/RequestedConvertFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RequestedConvertFileEvent.java new file mode 100644 index 00000000..f408efea --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/RequestedConvertFileEvent.java @@ -0,0 +1,71 @@ +package com.ss.builder.fx.event.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.file.converter.FileConverterDescription; +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.Event; +import javafx.event.EventType; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The event about request to covert a file. + * + * @author JavaSaBr + */ +public class RequestedConvertFileEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (Event.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedConvertFileEvent.class.getSimpleName()); + } + } + + private static final String FILE = "file"; + private static final String CONVERTER = "converter"; + + public RequestedConvertFileEvent(@NotNull FileConverterDescription description, @NotNull Path file) { + super(EVENT_TYPE); + setDescription(description); + setFile(file); + } + + /** + * Get the description. + * + * @return the converter description. + */ + public @NotNull FileConverterDescription getDescription() { + return notNull(get(CONVERTER)); + } + + /** + * Set the description. + * + * @param description the converter description. + */ + public void setDescription(@NotNull FileConverterDescription description) { + set(CONVERTER, description); + } + + /** + * Get the file. + * + * @return the file to convert. + */ + public @NotNull Path getFile() { + return notNull(get(FILE)); + } + + /** + * Set the file. + * + * @param file the file to convert. + */ + public void setFile(@NotNull Path file) { + set(FILE, file); + } +} diff --git a/src/main/java/com/ss/builder/fx/event/impl/RequestedCreateFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RequestedCreateFileEvent.java new file mode 100644 index 00000000..ee190b72 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/RequestedCreateFileEvent.java @@ -0,0 +1,71 @@ +package com.ss.builder.fx.event.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.fx.component.creator.FileCreatorDescriptor; +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.Event; +import javafx.event.EventType; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The event about request to create a new file. + * + * @author JavaSaBr + */ +public class RequestedCreateFileEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (Event.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedCreateFileEvent.class.getSimpleName()); + } + } + + private static final String FILE = "file"; + private static final String CREATOR = "creator"; + + public RequestedCreateFileEvent(@NotNull Path file, @NotNull FileCreatorDescriptor descriptor) { + super(EVENT_TYPE); + setFile(file); + setDescriptor(descriptor); + } + + /** + * Get the descriptor. + * + * @return the creator's descriptor. + */ + public @NotNull FileCreatorDescriptor getDescriptor() { + return notNull(get(CREATOR)); + } + + /** + * Set the descriptor. + * + * @param descriptor the creator's descriptor. + */ + public void setDescriptor(@NotNull FileCreatorDescriptor descriptor) { + set(CREATOR, descriptor); + } + + /** + * Get the file. + * + * @return the file. + */ + public @NotNull Path getFile() { + return notNull(get(FILE)); + } + + /** + * Set the file. + * + * @param file the file. + */ + public void setFile(@NotNull Path file) { + set(FILE, file); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/RequestedOpenFileEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RequestedOpenFileEvent.java similarity index 78% rename from src/main/java/com/ss/editor/ui/event/impl/RequestedOpenFileEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/RequestedOpenFileEvent.java index 224a5240..9c75aaed 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/RequestedOpenFileEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/RequestedOpenFileEvent.java @@ -1,8 +1,8 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.Event; import javafx.event.EventType; import org.jetbrains.annotations.NotNull; @@ -17,10 +17,7 @@ */ public class RequestedOpenFileEvent extends SceneEvent { - /** - * The constant EVENT_TYPE. - */ - public static final EventType EVENT_TYPE; + public static final EventType EVENT_TYPE; static { synchronized (Event.class) { @@ -38,12 +35,19 @@ public RequestedOpenFileEvent(@NotNull Path file) { setFile(file); } + public RequestedOpenFileEvent(@NotNull Path file, @NotNull EditorDescriptor description) { + super(EVENT_TYPE); + setNeedShow(true); + setFile(file); + setDescription(description); + } + /** * Get the description. * * @return the editor descriptor. */ - public @Nullable EditorDescription getDescription() { + public @Nullable EditorDescriptor getDescription() { return get(EDITOR); } @@ -52,7 +56,7 @@ public RequestedOpenFileEvent(@NotNull Path file) { * * @param description the editor descriptor. */ - public void setDescription(@Nullable EditorDescription description) { + public void setDescription(@Nullable EditorDescriptor description) { if (description == null) { remove(EDITOR); } else { diff --git a/src/main/java/com/ss/builder/fx/event/impl/RequestedRefreshAssetEvent.java b/src/main/java/com/ss/builder/fx/event/impl/RequestedRefreshAssetEvent.java new file mode 100644 index 00000000..7e39e3ef --- /dev/null +++ b/src/main/java/com/ss/builder/fx/event/impl/RequestedRefreshAssetEvent.java @@ -0,0 +1,25 @@ +package com.ss.builder.fx.event.impl; + +import com.ss.builder.fx.event.SceneEvent; +import javafx.event.Event; +import javafx.event.EventType; + +/** + * The event about request to refresh the current asset folder. + * + * @author JavaSaBr + */ +public class RequestedRefreshAssetEvent extends SceneEvent { + + public static final EventType EVENT_TYPE; + + static { + synchronized (Event.class) { + EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedRefreshAssetEvent.class.getSimpleName()); + } + } + + public RequestedRefreshAssetEvent() { + super(EVENT_TYPE); + } +} diff --git a/src/main/java/com/ss/editor/ui/event/impl/WindowChangeFocusEvent.java b/src/main/java/com/ss/builder/fx/event/impl/WindowChangeFocusEvent.java similarity index 92% rename from src/main/java/com/ss/editor/ui/event/impl/WindowChangeFocusEvent.java rename to src/main/java/com/ss/builder/fx/event/impl/WindowChangeFocusEvent.java index a942f24f..76b8eb14 100644 --- a/src/main/java/com/ss/editor/ui/event/impl/WindowChangeFocusEvent.java +++ b/src/main/java/com/ss/builder/fx/event/impl/WindowChangeFocusEvent.java @@ -1,6 +1,6 @@ -package com.ss.editor.ui.event.impl; +package com.ss.builder.fx.event.impl; -import com.ss.editor.ui.event.SceneEvent; +import com.ss.builder.fx.event.SceneEvent; import javafx.event.EventType; /** diff --git a/src/main/java/com/ss/editor/ui/preview/FilePreview.java b/src/main/java/com/ss/builder/fx/preview/FilePreview.java similarity index 93% rename from src/main/java/com/ss/editor/ui/preview/FilePreview.java rename to src/main/java/com/ss/builder/fx/preview/FilePreview.java index f2467736..cb6285d5 100644 --- a/src/main/java/com/ss/editor/ui/preview/FilePreview.java +++ b/src/main/java/com/ss/builder/fx/preview/FilePreview.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.preview; +package com.ss.builder.fx.preview; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.pools.Reusable; diff --git a/src/main/java/com/ss/editor/ui/preview/FilePreviewFactory.java b/src/main/java/com/ss/builder/fx/preview/FilePreviewFactory.java similarity index 77% rename from src/main/java/com/ss/editor/ui/preview/FilePreviewFactory.java rename to src/main/java/com/ss/builder/fx/preview/FilePreviewFactory.java index 96eb8825..02fa3099 100644 --- a/src/main/java/com/ss/editor/ui/preview/FilePreviewFactory.java +++ b/src/main/java/com/ss/builder/fx/preview/FilePreviewFactory.java @@ -1,6 +1,7 @@ -package com.ss.editor.ui.preview; +package com.ss.builder.fx.preview; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/fx/preview/FilePreviewFactoryRegistry.java b/src/main/java/com/ss/builder/fx/preview/FilePreviewFactoryRegistry.java new file mode 100644 index 00000000..9613cdb4 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/preview/FilePreviewFactoryRegistry.java @@ -0,0 +1,59 @@ +package com.ss.builder.fx.preview; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.preview.impl.DefaultFilePreviewFactory; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.preview.impl.DefaultFilePreviewFactory; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The registry with available factories of file previews. + * + * @author JavaSaBr + */ +public class FilePreviewFactoryRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(FilePreviewFactoryRegistry.class); + + /** + * @see FilePreviewFactory + */ + public static final String EP_PREVIEW_FACTORIES = "FilePreviewFactoryRegistry#previewFactories"; + + private static final ExtensionPoint PREVIEW_FACTORIES = + ExtensionPointManager.register(EP_PREVIEW_FACTORIES); + + private static final FilePreviewFactoryRegistry INSTANCE = new FilePreviewFactoryRegistry(); + + public static @NotNull FilePreviewFactoryRegistry getInstance() { + return INSTANCE; + } + + private FilePreviewFactoryRegistry() { + PREVIEW_FACTORIES.register(DefaultFilePreviewFactory.getInstance()); + LOGGER.info("initialized."); + } + + /** + * Create available of file previews. + * + * @return the list of available file previews. + */ + @FxThread + public Array createAvailablePreviews() { + + var result = Array.ofType(FilePreview.class); + + PREVIEW_FACTORIES.forEach(result, FilePreviewFactory::createFilePreviews); + + result.sort((first, second) -> + second.getOrder() - first.getOrder()); + + return result; + } +} diff --git a/src/main/java/com/ss/editor/ui/preview/impl/AbstractFilePreview.java b/src/main/java/com/ss/builder/fx/preview/impl/AbstractFilePreview.java similarity index 91% rename from src/main/java/com/ss/editor/ui/preview/impl/AbstractFilePreview.java rename to src/main/java/com/ss/builder/fx/preview/impl/AbstractFilePreview.java index 7a7f6c1f..76d17c3a 100644 --- a/src/main/java/com/ss/editor/ui/preview/impl/AbstractFilePreview.java +++ b/src/main/java/com/ss/builder/fx/preview/impl/AbstractFilePreview.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.preview.impl; +package com.ss.builder.fx.preview.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.preview.FilePreview; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.preview.FilePreview; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.Node; import javafx.scene.layout.StackPane; diff --git a/src/main/java/com/ss/editor/ui/preview/impl/DefaultFilePreviewFactory.java b/src/main/java/com/ss/builder/fx/preview/impl/DefaultFilePreviewFactory.java similarity index 76% rename from src/main/java/com/ss/editor/ui/preview/impl/DefaultFilePreviewFactory.java rename to src/main/java/com/ss/builder/fx/preview/impl/DefaultFilePreviewFactory.java index d38e7561..cf310b2a 100644 --- a/src/main/java/com/ss/editor/ui/preview/impl/DefaultFilePreviewFactory.java +++ b/src/main/java/com/ss/builder/fx/preview/impl/DefaultFilePreviewFactory.java @@ -1,8 +1,9 @@ -package com.ss.editor.ui.preview.impl; +package com.ss.builder.fx.preview.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.preview.FilePreview; -import com.ss.editor.ui.preview.FilePreviewFactory; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.preview.FilePreview; +import com.ss.builder.fx.preview.FilePreviewFactory; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/preview/impl/ImageFilePreview.java b/src/main/java/com/ss/builder/fx/preview/impl/ImageFilePreview.java similarity index 91% rename from src/main/java/com/ss/editor/ui/preview/impl/ImageFilePreview.java rename to src/main/java/com/ss/builder/fx/preview/impl/ImageFilePreview.java index d7d37c4a..a0bc8446 100644 --- a/src/main/java/com/ss/editor/ui/preview/impl/ImageFilePreview.java +++ b/src/main/java/com/ss/builder/fx/preview/impl/ImageFilePreview.java @@ -1,7 +1,9 @@ -package com.ss.editor.ui.preview.impl; +package com.ss.builder.fx.preview.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.JavaFxImageManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; import javafx.scene.image.ImageView; import javafx.scene.layout.StackPane; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/preview/impl/JmeObjectFilePreview.java b/src/main/java/com/ss/builder/fx/preview/impl/JmeObjectFilePreview.java similarity index 91% rename from src/main/java/com/ss/editor/ui/preview/impl/JmeObjectFilePreview.java rename to src/main/java/com/ss/builder/fx/preview/impl/JmeObjectFilePreview.java index 20c692c3..b235787e 100644 --- a/src/main/java/com/ss/editor/ui/preview/impl/JmeObjectFilePreview.java +++ b/src/main/java/com/ss/builder/fx/preview/impl/JmeObjectFilePreview.java @@ -1,7 +1,9 @@ -package com.ss.editor.ui.preview.impl; +package com.ss.builder.fx.preview.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.JmeFilePreviewManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JmeFilePreviewManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JmeFilePreviewManager; import javafx.scene.image.ImageView; import javafx.scene.layout.StackPane; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/ui/preview/impl/TextFilePreview.java b/src/main/java/com/ss/builder/fx/preview/impl/TextFilePreview.java similarity index 80% rename from src/main/java/com/ss/editor/ui/preview/impl/TextFilePreview.java rename to src/main/java/com/ss/builder/fx/preview/impl/TextFilePreview.java index dac5203a..8b0a2675 100644 --- a/src/main/java/com/ss/editor/ui/preview/impl/TextFilePreview.java +++ b/src/main/java/com/ss/builder/fx/preview/impl/TextFilePreview.java @@ -1,9 +1,13 @@ -package com.ss.editor.ui.preview.impl; +package com.ss.builder.fx.preview.impl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.fx.util.FXUtils; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.Utils; @@ -62,7 +66,7 @@ public void show(@NotNull final String resource) { if (url != null) { content = Utils.get(url, toRead -> FileUtils.read(toRead.openStream())); } else { - final Path realFile = EditorUtil.getRealFile(resource); + final Path realFile = EditorUtils.getRealFile(resource); content = realFile == null ? "" : FileUtils.read(realFile); } diff --git a/src/main/java/com/ss/editor/ui/scene/EditorFxImageView.java b/src/main/java/com/ss/builder/fx/scene/EditorFxImageView.java similarity index 96% rename from src/main/java/com/ss/editor/ui/scene/EditorFxImageView.java rename to src/main/java/com/ss/builder/fx/scene/EditorFxImageView.java index 61e47dba..5674dac3 100644 --- a/src/main/java/com/ss/editor/ui/scene/EditorFxImageView.java +++ b/src/main/java/com/ss/builder/fx/scene/EditorFxImageView.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.scene; +package com.ss.builder.fx.scene; import javafx.scene.image.ImageView; diff --git a/src/main/java/com/ss/editor/ui/scene/EditorFxScene.java b/src/main/java/com/ss/builder/fx/scene/EditorFxScene.java similarity index 88% rename from src/main/java/com/ss/editor/ui/scene/EditorFxScene.java rename to src/main/java/com/ss/builder/fx/scene/EditorFxScene.java index 9ce78aaf..9fc5d513 100644 --- a/src/main/java/com/ss/editor/ui/scene/EditorFxScene.java +++ b/src/main/java/com/ss/builder/fx/scene/EditorFxScene.java @@ -1,13 +1,15 @@ -package com.ss.editor.ui.scene; +package com.ss.builder.fx.scene; -import static com.ss.editor.ui.util.UiUtils.fillComponents; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.jfx.injfx.input.JfxMouseInput; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.InitializationManager; -import com.ss.editor.ui.component.ScreenComponent; -import com.ss.editor.ui.css.CssIds; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.component.ScreenComponent; +import com.ss.builder.fx.css.CssIds; +import com.ss.builder.fx.event.impl.EditorFinishedLoadingEvent; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.manager.AsyncEventManager; +import com.ss.builder.manager.ExecutorManager; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -152,7 +154,7 @@ public void hideCanvas() { @FxThread public @Nullable T findComponent(@NotNull String id) { var components = getComponents(); - return unsafeCast(components.search(id, (component, toCheck) -> + return unsafeCast(components.findAny(id, (component, toCheck) -> StringUtils.equals(toCheck, component.getComponentId()))); } @@ -264,14 +266,16 @@ private void hideLoading() { /** * Notify all components about finished building. */ - @FxThread + @BackgroundThread public void notifyFinishBuild() { - var components = getComponents(); - fillComponents(components, getContainer()); - components.forEach(ScreenComponent::notifyFinishBuild); + UiUtils.fillComponents(getComponents(), getContainer()) + .forEach(ScreenComponent::notifyFinishBuild); + + ExecutorManager.getInstance() + .addFxTask(this::decrementLoading); - var initializationManager = InitializationManager.getInstance(); - initializationManager.onFinishLoading(); + AsyncEventManager.getInstance() + .notify(new EditorFinishedLoadingEvent()); } } diff --git a/src/main/java/com/ss/editor/ui/tooltip/CustomTooltip.java b/src/main/java/com/ss/builder/fx/tooltip/CustomTooltip.java similarity index 86% rename from src/main/java/com/ss/editor/ui/tooltip/CustomTooltip.java rename to src/main/java/com/ss/builder/fx/tooltip/CustomTooltip.java index 959e16f8..44d550de 100644 --- a/src/main/java/com/ss/editor/ui/tooltip/CustomTooltip.java +++ b/src/main/java/com/ss/builder/fx/tooltip/CustomTooltip.java @@ -1,7 +1,9 @@ -package com.ss.editor.ui.tooltip; +package com.ss.builder.fx.tooltip; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.Scene; import javafx.scene.control.Tooltip; diff --git a/src/main/java/com/ss/editor/ui/tooltip/ImageChannelPreview.java b/src/main/java/com/ss/builder/fx/tooltip/ImageChannelPreview.java similarity index 96% rename from src/main/java/com/ss/editor/ui/tooltip/ImageChannelPreview.java rename to src/main/java/com/ss/builder/fx/tooltip/ImageChannelPreview.java index 048a929d..a4801d32 100644 --- a/src/main/java/com/ss/editor/ui/tooltip/ImageChannelPreview.java +++ b/src/main/java/com/ss/builder/fx/tooltip/ImageChannelPreview.java @@ -1,9 +1,12 @@ -package com.ss.editor.ui.tooltip; +package com.ss.builder.fx.tooltip; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.JavaFxImageManager; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.image.*; import javafx.scene.layout.GridPane; diff --git a/src/main/java/com/ss/editor/ui/tooltip/ImagePreview.java b/src/main/java/com/ss/builder/fx/tooltip/ImagePreview.java similarity index 87% rename from src/main/java/com/ss/editor/ui/tooltip/ImagePreview.java rename to src/main/java/com/ss/builder/fx/tooltip/ImagePreview.java index fc6be478..baca71be 100644 --- a/src/main/java/com/ss/editor/ui/tooltip/ImagePreview.java +++ b/src/main/java/com/ss/builder/fx/tooltip/ImagePreview.java @@ -1,9 +1,12 @@ -package com.ss.editor.ui.tooltip; +package com.ss.builder.fx.tooltip; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.JavaFxImageManager; -import com.ss.editor.ui.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.JavaFxImageManager; +import com.ss.builder.fx.css.CssClasses; import com.ss.rlib.fx.util.FXUtils; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; diff --git a/src/main/java/com/ss/editor/ui/util/AwtFontSuggestionProvider.java b/src/main/java/com/ss/builder/fx/util/AwtFontSuggestionProvider.java similarity index 98% rename from src/main/java/com/ss/editor/ui/util/AwtFontSuggestionProvider.java rename to src/main/java/com/ss/builder/fx/util/AwtFontSuggestionProvider.java index e4cabd03..794a5575 100644 --- a/src/main/java/com/ss/editor/ui/util/AwtFontSuggestionProvider.java +++ b/src/main/java/com/ss/builder/fx/util/AwtFontSuggestionProvider.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.util; +package com.ss.builder.fx.util; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/editor/ui/util/DynamicIconSupport.java b/src/main/java/com/ss/builder/fx/util/DynamicIconSupport.java similarity index 94% rename from src/main/java/com/ss/editor/ui/util/DynamicIconSupport.java rename to src/main/java/com/ss/builder/fx/util/DynamicIconSupport.java index 5b05a607..9ae7901d 100644 --- a/src/main/java/com/ss/editor/ui/util/DynamicIconSupport.java +++ b/src/main/java/com/ss/builder/fx/util/DynamicIconSupport.java @@ -1,11 +1,11 @@ -package com.ss.editor.ui.util; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.FileIconManager; -import com.ss.editor.ui.css.CssColorTheme; +package com.ss.builder.fx.util; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.manager.FileIconManager; +import com.ss.builder.fx.css.CssColorTheme; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.collections.ObservableMap; diff --git a/src/main/java/com/ss/editor/ui/util/SimpleStringSuggestionProvider.java b/src/main/java/com/ss/builder/fx/util/SimpleStringSuggestionProvider.java similarity index 98% rename from src/main/java/com/ss/editor/ui/util/SimpleStringSuggestionProvider.java rename to src/main/java/com/ss/builder/fx/util/SimpleStringSuggestionProvider.java index 13c2f386..02db73a2 100644 --- a/src/main/java/com/ss/editor/ui/util/SimpleStringSuggestionProvider.java +++ b/src/main/java/com/ss/builder/fx/util/SimpleStringSuggestionProvider.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.util; +package com.ss.builder.fx.util; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; diff --git a/src/main/java/com/ss/builder/fx/util/UiUtils.java b/src/main/java/com/ss/builder/fx/util/UiUtils.java new file mode 100644 index 00000000..d2c68675 --- /dev/null +++ b/src/main/java/com/ss/builder/fx/util/UiUtils.java @@ -0,0 +1,1060 @@ +package com.ss.builder.fx.util; + +import static com.ss.builder.util.EditorUtils.getFxScene; +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import static java.lang.Math.min; +import com.jme3.math.ColorRGBA; +import com.ss.builder.fx.dialog.save.SaveAsEditorDialog; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.UObject; +import com.ss.builder.fx.component.ScreenComponent; +import com.ss.builder.fx.dialog.asset.BaseAssetEditorDialog; +import com.ss.builder.fx.dialog.asset.file.AssetEditorDialog; +import com.ss.builder.fx.dialog.asset.file.FileAssetEditorDialog; +import com.ss.builder.fx.dialog.asset.file.FolderAssetEditorDialog; +import com.ss.builder.fx.dialog.asset.virtual.StringVirtualAssetEditorDialog; +import com.ss.builder.fx.dialog.save.SaveAsEditorDialog; +import com.ss.rlib.common.util.ArrayUtils; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.BooleanPropertyBase; +import javafx.beans.value.ChangeListener; +import javafx.collections.ObservableList; +import javafx.css.PseudoClass; +import javafx.event.EventTarget; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.*; +import javafx.scene.input.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.util.Duration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.reactfx.util.TriConsumer; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * The utility class with utility UI methods. + * + * @author JavaSaBr + */ +public abstract class UiUtils { + + private static final PseudoClass FOCUSED_PSEUDO_CLASS = PseudoClass.getPseudoClass("focused"); + + private static final Duration TOOLTIP_HIDE_DELAY = new Duration(100); + private static final Duration TOOLTIP_SHOW_DELAY = new Duration(1000); + private static final Duration TOOLTIP_SHOW_DURATION = new Duration(5000); + + /** + * Add binding pseudo focus of the pane to focus state of the controls. + * + * @param pane the pane. + * @param controls the controls. + */ + @FxThread + public static @NotNull BooleanProperty addFocusBinding(@NotNull Pane pane, @NotNull Control... controls) { + + var focused = new BooleanPropertyBase(true) { + + @Override + public void invalidated() { + pane.pseudoClassStateChanged(FOCUSED_PSEUDO_CLASS, get()); + } + + @Override + public Object getBean() { + return pane; + } + + @Override + public String getName() { + return "focused"; + } + }; + + ChangeListener listener = (observable, oldValue, newValue) -> + focused.setValue(newValue || ArrayUtils.anyMatch(controls, Node::isFocused)); + + for (var control : controls) { + control.focusedProperty().addListener(listener); + control.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> control.requestFocus()); + } + + focused.setValue(ArrayUtils.anyMatch(controls, Node::isFocused)); + + return focused; + } + + /** + * Clear children of the pane. + * + * @param pane the pane. + */ + @FxThread + public static void clear(@NotNull Pane pane) { + var children = pane.getChildren(); + children.forEach(UiUtils::unbind); + children.clear(); + } + + /** + * Unbind a node. + * + * @param node the node. + */ + @FxThread + private static void unbind(@NotNull Node node) { + if (node instanceof Control) { + var control = (Control) node; + control.prefWidthProperty().unbind(); + control.prefHeightProperty().unbind(); + } else if (node instanceof Pane) { + var pane = (Pane) node; + pane.prefHeightProperty().unbind(); + pane.prefWidthProperty().unbind(); + } + } + + /** + * Fill a list of components. + * + * @param container the container. + * @param node the node. + */ + @FromAnyThread + public static @NotNull Array fillComponents( + @NotNull Array container, + @NotNull Node node + ) { + + if (node instanceof ScreenComponent) { + container.add((ScreenComponent) node); + } + + if (node instanceof SplitPane) { + var items = ((SplitPane) node).getItems(); + items.forEach(child -> fillComponents(container, child)); + } else if (node instanceof TabPane) { + var tabs = ((TabPane) node).getTabs(); + tabs.forEach(tab -> fillComponents(container, tab.getContent())); + } + + if (!(node instanceof Parent)) { + return container; + } + + var nodes = ((Parent) node).getChildrenUnmodifiable(); + nodes.forEach(child -> fillComponents(container, child)); + + return container; + } + + /** + * Get all components of the type. + * + * @param the component's type. + * @param node the node. + * @param type the type. + * @return the found components. + */ + @FxThread + public static @NotNull Array getComponents(@NotNull Node node, @NotNull Class type) { + var container = Array.ofType(type); + fillComponents(container, node, type); + return container; + } + + /** + * Find all components for a type. + * + * @param the type parameter + * @param container the container + * @param node the node + * @param type the type + */ + @FxThread + public static void fillComponents( + @NotNull Array container, + @NotNull Node node, + @NotNull Class type + ) { + + if (type.isInstance(container)) { + container.add(type.cast(node)); + } + + if (!(node instanceof Parent)) { + return; + } + + ((Parent) node).getChildrenUnmodifiable() + .forEach(child -> fillComponents(container, child, type)); + } + + /** + * Get all elements of the menu. + * + * @param menuBar the menu bar. + * @return the all items. + */ + @FxThread + public static @NotNull Array getAllItems(@NotNull MenuBar menuBar) { + + var container = Array.ofType(MenuItem.class); + + menuBar.getMenus() + .forEach(menu -> getAllItems(container, menu)); + + return container; + } + + /** + * Collect all elements of a menu. + */ + @FxThread + private static void getAllItems(@NotNull Array container, @NotNull MenuItem menuItem) { + + container.add(menuItem); + + if (!(menuItem instanceof Menu)) { + return; + } + + ((Menu) menuItem).getItems() + .forEach(subMenuItem -> getAllItems(container, subMenuItem)); + } + + /** + * Collect all items. + * + * @param container the container + * @param menuButton the menu button + */ + @FxThread + public static void getAllItems(@NotNull final Array container, @NotNull final MenuButton menuButton) { + final ObservableList items = menuButton.getItems(); + items.forEach(subMenuItem -> getAllItems(container, subMenuItem)); + } + + /** + * Add to. + * + * @param item the item + * @param parent the parent + */ + @FxThread + public static void addTo(@NotNull final TreeItem item, + @NotNull final TreeItem parent) { + final ObservableList> children = parent.getChildren(); + children.add(item); + } + + /** + * Update behaviour of the tooltip. + * + * @param tooltip the tooltip. + * @return the updated tooltip. + */ + @FxThread + public static T updateTooltip(final T tooltip) { + tooltip.setHideDelay(TOOLTIP_HIDE_DELAY); + tooltip.setShowDelay(TOOLTIP_SHOW_DELAY); + tooltip.setShowDuration(TOOLTIP_SHOW_DURATION); + return tooltip; + } + + /** + * Find a tree item by object id. + * + * @param the type parameter + * @param treeView the tree. + * @param objectId the object id. + * @return the tree item or null. + */ + @FxThread + public static @Nullable TreeItem findItem(@NotNull final TreeView treeView, final long objectId) { + return findItem(treeView.getRoot(), objectId); + } + + /** + * Find a tree item by object id. + * + * @param the type parameter + * @param root the root item. + * @param objectId the object id. + * @return the tree item or null. + */ + @FxThread + public static @Nullable TreeItem findItem(@NotNull final TreeItem root, final long objectId) { + + final T value = root.getValue(); + + if (value instanceof UObject && ((UObject) value).getObjectId() == objectId) { + return root; + } + + final ObservableList> children = root.getChildren(); + + if (!children.isEmpty()) { + for (final TreeItem treeItem : children) { + final TreeItem result = findItem(treeItem, objectId); + if (result != null) return result; + } + } + + return null; + } + + /** + * Find a tree item by its value. + * + * @param the type parameter + * @param treeView the tree view. + * @param object the value. + * @return the tree item or null. + */ + @FxThread + public static @Nullable TreeItem findItemForValue(@NotNull final TreeView treeView, @Nullable final Object object) { + return findItemForValue(treeView.getRoot(), object); + } + + /** + * Find a tree item by its value. + * + * @param the type parameter + * @param root the root item. + * @param object the value. + * @return the tree item or null. + */ + @FxThread + public @Nullable static TreeItem findItemForValue(@NotNull final TreeItem root, @Nullable final Object object) { + + if (object == null) { + return null; + } else if (Objects.equals(root.getValue(), object)) { + return root; + } + + final ObservableList> children = root.getChildren(); + + if (!children.isEmpty()) { + for (final TreeItem treeItem : children) { + final TreeItem result = findItemForValue(treeItem, object); + if (result != null) { + return result; + } + } + } + + return null; + } + + /** + * Get all elements of a tree view. + * + * @param the type parameter + * @param treeView the tree view. + * @return the list of all items. + */ + @FxThread + public static @NotNull Array> getAllItems(@NotNull final TreeView treeView) { + + final Array> container = ArrayFactory.newArray(TreeItem.class); + + final TreeItem root = treeView.getRoot(); + final ObservableList> children = root.getChildren(); + + for (final TreeItem child : children) { + collectAllItems(container, child); + } + + return container; + } + + /** + * Visit all items. + * + * @param the type parameter. + * @param item the tree item. + * @param visitor the visitor. + */ + @FxThread + public static void visit(@NotNull final TreeItem item, @NotNull final Consumer> visitor) { + visitor.accept(item); + + final ObservableList> children = item.getChildren(); + if (children.isEmpty()) return; + + for (final TreeItem child : children) { + visit(child, visitor); + } + } + + /** + * Visit all items. + * + * @param the type parameter. + * @param item the tree item. + * @param visitor the visitor. + * @return true of we can visit child elements. + */ + @FxThread + public static boolean visitUntil(@NotNull final TreeItem item, + @NotNull final Predicate> visitor) { + + if (!visitor.test(item)) return false; + + final ObservableList> children = item.getChildren(); + if (children.isEmpty()) return true; + + for (final TreeItem child : children) { + if (!visitUntil(child, visitor)) return false; + } + + return true; + } + + /** + * Collect all elements of tree items. + * + * @param the type parameter + * @param root the tree item. + * @return the list with all items. + */ + @FxThread + public static Array> getAllItems(@NotNull TreeItem root) { + final Array> container = ArrayFactory.newArray(TreeItem.class); + collectAllItems(container, root); + return container; + } + + /** + * Collect all elements of tree items. + * + * @param the type parameter + * @param root the tree item. + * @return the list with all items. + */ + @FxThread + public static Stream> allItems(@NotNull TreeItem root) { + Array> container = ArrayFactory.newArray(TreeItem.class); + collectAllItems(container, root); + return container.stream(); + } + + /** + * Collect all elements of tree items. + * + * @param the type parameter + * @param container the container. + * @param root the tree item. + */ + @FxThread + public static void collectAllItems(@NotNull final Array> container, @NotNull final TreeItem root) { + + container.add(root); + + final ObservableList> children = root.getChildren(); + + for (final TreeItem child : children) { + collectAllItems(container, child); + } + } + + /** + * Convert a color from {@link Color} to {@link ColorRGBA}. + * + * @param color the color + * @return the jme color + */ + @FxThread + public static @Nullable ColorRGBA from(@Nullable Color color) { + + if (color == null) { + return null; + } + + return new ColorRGBA((float) color.getRed(), (float) color.getGreen(), + (float) color.getBlue(), (float) color.getOpacity()); + } + + /** + * Convert a color from {@link ColorRGBA} to {@link Color}. + * + * @param color the color + * @return the FX color + */ + @FxThread + public static @Nullable Color from(@Nullable final ColorRGBA color) { + if (color == null) return null; + + final float red = min(color.getRed(), 1F); + final float green = min(color.getGreen(), 1F); + final float blue = min(color.getBlue(), 1F); + final float alpha = min(color.getAlpha(), 1F); + + return new Color(red, green, blue, alpha); + } + + /** + * @param event the event. + * @return true if the event is not hotkey. + */ + @FxThread + public static boolean isNotHotKey(@Nullable final KeyEvent event) { + if (event == null) return false; + + final String text = event.getText(); + if (text.isEmpty()) return false; + + final KeyCode code = event.getCode(); + final EventTarget target = event.getTarget(); + + if (code == KeyCode.TAB && !(target instanceof TextInputControl)) { + return false; + } + + if (event.isControlDown()) { + return false; + } else return !event.isShiftDown(); + } + + /** + * Consume an event if the condition returns true. + * + * @param event the event. + * @param condition the condition. + */ + @FxThread + public static void consumeIf(@NotNull final KeyEvent event, @NotNull final Predicate condition) { + if (condition.test(event)) { + event.consume(); + } + } + + /** + * Consume an event if the event is not hotkey. + * + * @param event the event. + */ + @FxThread + public static void consumeIfIsNotHotKey(@Nullable final KeyEvent event) { + + if (event == null) { + return; + } + + final KeyCode code = event.getCode(); + if (code == KeyCode.ESCAPE || code == KeyCode.ENTER) { + return; + } + + if (isNotHotKey(event)) { + event.consume(); + } + } + + /** + * Update an edited cell. + * + * @param cell the edited cell. + */ + @FxThread + public static void updateEditedCell(final Labeled cell) { + + final javafx.scene.Node graphic = cell.getGraphic(); + + if (graphic instanceof HBox) { + final HBox hbox = (HBox) graphic; + hbox.setAlignment(Pos.CENTER_LEFT); + hbox.setMinHeight(cell.getMinHeight()); + } + } + + /** + * Open an resource asset dialog. + * + * @param handler the result handler. + * @param resources the resources. + */ + @FxThread + public static void openResourceAssetDialog(@NotNull final Consumer handler, + @NotNull final Array resources) { + openResourceAssetDialog(handler, null, resources); + } + + /** + * Open an resource asset dialog. + * + * @param handler the result handler. + * @param validator the validator. + * @param resources the resources. + */ + @FxThread + public static void openResourceAssetDialog( + @NotNull Consumer handler, + @Nullable BaseAssetEditorDialog.Validator validator, + @NotNull Array resources + ) { + new StringVirtualAssetEditorDialog(handler, validator, resources).show(); + } + + /** + * Open an asset dialog. + * + * @param handler the result handler. + * @param extensions the extensions list. + * @param actionTester the action tester. + */ + @FxThread + public static void openFileAssetDialog(@NotNull final Consumer handler, + @NotNull final Array extensions, + @Nullable final Predicate> actionTester) { + + final AssetEditorDialog dialog = new FileAssetEditorDialog(handler); + dialog.setExtensionFilter(extensions); + dialog.setActionTester(actionTester); + dialog.show(); + } + + /** + * Open an asset dialog. + * + * @param handler the result handler. + * @param actionTester the action tester. + */ + @FxThread + public static void openFolderAssetDialog(@NotNull final Consumer handler, + @Nullable final Predicate> actionTester) { + + final AssetEditorDialog dialog = new FolderAssetEditorDialog(handler); + dialog.setActionTester(actionTester); + dialog.show(); + } + + /** + * Open a save as dialog. + * + * @param handler the result handler. + * @param extension the file extension. + * @param actionTester the action tester. + */ + @FxThread + public static void openSaveAsDialog(@NotNull final Consumer<@NotNull Path> handler, @NotNull final String extension, + @Nullable final Predicate<@NotNull Class> actionTester) { + + final SaveAsEditorDialog dialog = new SaveAsEditorDialog(handler); + dialog.setExtension(extension); + + if (actionTester != null) { + dialog.setActionTester(actionTester); + } + + dialog.show(); + } + + /** + * Accept a transfer mode for the event. + * + * @param dragEvent the drag event. + * @param dragboard the dragboard. + */ + @FxThread + private static void acceptTransferMode(@NotNull DragEvent dragEvent, @NotNull Dragboard dragboard) { + + var transferModes = dragboard.getTransferModes(); + var isCopy = transferModes.contains(TransferMode.COPY); + + dragEvent.acceptTransferModes(isCopy ? TransferMode.COPY : TransferMode.MOVE); + dragEvent.consume(); + } + + /** + * Get a file from the dragboard. + * + * @param dragboard the dragboard. + * @return the file or null. + */ + @FxThread + private static @Nullable File getDragboardFile(@NotNull Dragboard dragboard) { + + var files = ClassUtils.>unsafeCast(dragboard.getContent(DataFormat.FILES)); + + if (files == null || files.size() != 1) { + return null; + } + + return files.get(0); + } + + /** + * Get a file from the dragboard. + * + * @param dragboard the dragboard. + * @return the optional value of the file. + */ + private static @NotNull Optional getDragboardFileOpt(@NotNull Dragboard dragboard) { + return Optional.ofNullable(getDragboardFile(dragboard)); + } + + /** + * Accept a drag event if it has a file with required extensions. + * + * @param dragEvent the drag event. + * @param extensions the extensions. + */ + @FxThread + public static void acceptIfHasFile(@NotNull DragEvent dragEvent, @NotNull Array extensions) { + + var dragboard = dragEvent.getDragboard(); + + if (isHasFile(dragboard, extensions)) { + acceptTransferMode(dragEvent, dragboard); + } + } + + /** + * Accept a drag event if it has a file with required extension. + * + * @param dragEvent the drag event. + * @param targetExtension the extension. + */ + @FxThread + public static void acceptIfHasFile(@NotNull DragEvent dragEvent, @NotNull String targetExtension) { + + var dragboard = dragEvent.getDragboard(); + + if (isHasFile(dragboard, targetExtension)) { + acceptTransferMode(dragEvent, dragboard); + } + } + + /** + * Accept a drag event if it has a file with required extension. + * + * @param dragEvent the drag event. + * @param checker the checker. + */ + @FxThread + public static void acceptIfHasFile(@NotNull DragEvent dragEvent, @NotNull Function checker) { + + var dragboard = dragEvent.getDragboard(); + + if (!isHasFile(dragboard, checker)) { + acceptTransferMode(dragEvent, dragboard); + } + } + + /** + * Return true if there are required file. + * + * @param dragboard the dragboard. + * @param extensions the extensions. + * @return true if there are required file. + */ + @FxThread + public static boolean isHasFile(@NotNull Dragboard dragboard, @NotNull Array extensions) { + return getDragboardFileOpt(dragboard) + .map(file -> FileUtils.getExtension(file.getName(), true)) + .map(extensions::contains) + .orElse(false); + } + + /** + * Return true if there are required file. + * + * @param dragboard the dragboard. + * @param targetExtension the target extension. + * @return true if there are required file. + */ + @FxThread + public static boolean isHasFile(@NotNull Dragboard dragboard, @NotNull String targetExtension) { + return getDragboardFileOpt(dragboard) + .map(file -> FileUtils.getExtension(file.getName(), true)) + .map(targetExtension::equalsIgnoreCase) + .orElse(false); + } + + /** + * Return true if there are required file. + * + * @param dragboard the dragboard. + * @param checker the checker. + * @return true if there are required file. + */ + @FxThread + public static boolean isHasFile(@NotNull Dragboard dragboard, @NotNull Function checker) { + return getDragboardFileOpt(dragboard) + .map(checker) + .orElse(false); + } + + /** + * Handle a first dropped file if it has required extensions. + * + * @param dragEvent the drag event. + * @param handler the handler. + */ + @FxThread + public static void handleDroppedFile( + @NotNull DragEvent dragEvent, + @NotNull Consumer handler + ) { + getDragboardFileOpt(dragEvent.getDragboard()) + .map(File::toPath) + .ifPresent(handler); + } + + /** + * Handle a first dropped file if it has required extensions. + * + * @param firstArg the first argument. + * @param handler the handler. + * @param the first arg's type. + */ + @FxThread + public static void handleDroppedFile( + @NotNull DragEvent dragEvent, + @NotNull F firstArg, + @NotNull BiConsumer handler + ) { + getDragboardFileOpt(dragEvent.getDragboard()) + .map(File::toPath) + .ifPresent(path -> handler.accept(firstArg, path)); + } + + /** + * Handle a first dropped file if it has required extensions. + * + * @param dragEvent the drag event. + * @param extension the extension. + * @param firstArg the first argument. + * @param handler the handler. + * @param the first arg's type. + */ + @FxThread + public static void handleDroppedFile( + @NotNull DragEvent dragEvent, + @NotNull String extension, + @NotNull F firstArg, + @NotNull BiConsumer handler + ) { + getDragboardFileOpt(dragEvent.getDragboard()) + .map(File::toPath) + .filter(file -> extension.equalsIgnoreCase(FileUtils.getExtension(file))) + .ifPresent(path -> handler.accept(firstArg, path)); + } + + + /** + * Handle a first dropped file if it has required extensions. + * + * @param dragEvent the drag event. + * @param firstArg the first argument. + * @param secondArg the second argument. + * @param handler the handler. + * @param the first arg's type. + * @param the second arg's type. + */ + @FxThread + public static void handleDroppedFile( + @NotNull DragEvent dragEvent, + @NotNull F firstArg, + @NotNull S secondArg, + @NotNull TriConsumer handler + ) { + handleDroppedFile(dragEvent.getDragboard(), firstArg, secondArg, handler); + } + + /** + * Handle a first dropped file if it has required extensions. + * + * @param dragEvent the drag event. + * @param extension the extension. + * @param firstArg the first argument. + * @param secondArg the second argument. + * @param handler the handler. + * @param the first arg's type. + * @param the second arg's type. + */ + @FxThread + public static void handleDroppedFile( + @NotNull DragEvent dragEvent, + @NotNull F firstArg, + @NotNull S secondArg, + @NotNull String extension, + @NotNull TriConsumer handler + ) { + getDragboardFileOpt(dragEvent.getDragboard()) + .map(File::toPath) + .filter(file -> extension.equalsIgnoreCase(FileUtils.getExtension(file))) + .ifPresent(path -> handler.accept(firstArg, secondArg, path)); + } + + /** + * Handle a first dropped file if it has required extensions. + * + * @param the type parameter + * @param the type parameter + * @param dragboard the dragboard. + * @param firstArg the first argument. + * @param secondArg the second argument. + * @param handler the handler. + */ + @FxThread + public static void handleDroppedFile( + @NotNull Dragboard dragboard, + @NotNull F firstArg, + @NotNull S secondArg, + @NotNull TriConsumer handler + ) { + getDragboardFileOpt(dragboard) + .map(File::toPath) + .ifPresent(path -> handler.accept(firstArg, secondArg, path)); + } + + /** + * Convert the color to hex presentation to use in web. + * + * @param color the color. + * @return the web presentation. + */ + @FromAnyThread + public static @NotNull String toWeb(@NotNull final Color color) { + int red = (int) (color.getRed() * 255); + int green = (int) (color.getGreen() * 255); + int blue = (int) (color.getBlue() * 255); + return "#" + Integer.toHexString(red) + Integer.toHexString(green) + Integer.toHexString(blue); + } + + /** + * Increment the loading counter. + */ + @FromAnyThread + public static void incrementLoading() { + + if (Platform.isFxApplicationThread()) { + getFxScene().incrementLoading(); + } else { + ExecutorManager.getInstance() + .addFxTask(UiUtils::incrementLoading); + } + } + + /** + * Decrement the loading counter. + */ + @FromAnyThread + public static void decrementLoading() { + + if (Platform.isFxApplicationThread()) { + getFxScene().decrementLoading(); + } else { + ExecutorManager.getInstance() + .addFxTask(UiUtils::decrementLoading); + } + } + + /** + * Create a dialog for showing the exception. + */ + @FxThread + public static @NotNull Alert createErrorAlert( + @NotNull Throwable e, + @Nullable String localizedMessage, + @Nullable String stackTrace + ) { + + var textArea = new TextArea(stackTrace); + textArea.setEditable(false); + textArea.setWrapText(true); + + VBox.setMargin(textArea, new Insets(2, 5, 2, 5)); + + var alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText(StringUtils.isEmpty(localizedMessage) ? e.getClass().getSimpleName() : localizedMessage); + + var dialogPane = alert.getDialogPane(); + dialogPane.setExpandableContent(new VBox(textArea)); + dialogPane.expandedProperty().addListener((observable, oldValue, newValue) -> { + + if (newValue == Boolean.TRUE) { + alert.setWidth(800); + alert.setHeight(400); + } else { + alert.setWidth(500); + alert.setHeight(220); + } + }); + + return alert; + } + + /** + * Check of existing a file in clipboard. + * + * @return true if you have a file in your system clipboard. + */ + @FxThread + public static boolean hasFileInClipboard() { + final Clipboard clipboard = Clipboard.getSystemClipboard(); + if (clipboard == null) return false; + final List files = unsafeCast(clipboard.getContent(DataFormat.FILES)); + return !(files == null || files.isEmpty()); + } + + /** + * Find a menu item by the item's type. + * + * @param items the item list. + * @param type the item's type. + * @param the item's type. + * @return the found item or null. + */ + @FxThread + public static @Nullable T findMenuItem(@NotNull final List items, + @NotNull final Class type) { + for (final MenuItem item : items) { + + if (type.isInstance(item)) { + return type.cast(item); + } + + if (item instanceof Menu) { + final T result = findMenuItem(((Menu) item).getItems(), type); + if (result != null) { + return result; + } + } + } + + return null; + } + + private UiUtils() { + throw new RuntimeException(); + } +} diff --git a/src/main/java/com/ss/editor/asset/locator/FileSystemAssetLocator.java b/src/main/java/com/ss/builder/jme/asset/locator/FileSystemAssetLocator.java similarity index 80% rename from src/main/java/com/ss/editor/asset/locator/FileSystemAssetLocator.java rename to src/main/java/com/ss/builder/jme/asset/locator/FileSystemAssetLocator.java index 4ee7cde0..1314e582 100644 --- a/src/main/java/com/ss/editor/asset/locator/FileSystemAssetLocator.java +++ b/src/main/java/com/ss/builder/jme/asset/locator/FileSystemAssetLocator.java @@ -1,11 +1,13 @@ -package com.ss.editor.asset.locator; +package com.ss.builder.jme.asset.locator; -import static com.ss.editor.util.EditorUtil.getAssetManager; +import static com.ss.builder.util.EditorUtils.getAssetManager; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetKey; import com.jme3.asset.AssetLocator; import com.jme3.asset.AssetManager; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; import com.ss.rlib.common.util.ArrayUtils; import com.ss.rlib.common.util.array.ArrayFactory; import com.ss.rlib.common.util.array.ConcurrentArray; @@ -33,7 +35,7 @@ public class FileSystemAssetLocator implements AssetLocator { public static void clear() { final long stamp = LOCATED_KEYS.writeLock(); try { - LOCATED_KEYS.forEach(getAssetManager(), (assetKey, manager) -> manager.deleteFromCache(assetKey)); + LOCATED_KEYS.forEach(EditorUtils.getAssetManager(), (assetKey, manager) -> manager.deleteFromCache(assetKey)); } finally { LOCATED_KEYS.writeUnlock(stamp); } diff --git a/src/main/java/com/ss/editor/asset/locator/FolderAssetLocator.java b/src/main/java/com/ss/builder/jme/asset/locator/FolderAssetLocator.java similarity index 91% rename from src/main/java/com/ss/editor/asset/locator/FolderAssetLocator.java rename to src/main/java/com/ss/builder/jme/asset/locator/FolderAssetLocator.java index 29730fc7..1f82cbcf 100644 --- a/src/main/java/com/ss/editor/asset/locator/FolderAssetLocator.java +++ b/src/main/java/com/ss/builder/jme/asset/locator/FolderAssetLocator.java @@ -1,11 +1,13 @@ -package com.ss.editor.asset.locator; +package com.ss.builder.jme.asset.locator; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetKey; import com.jme3.asset.AssetLocator; import com.jme3.asset.AssetManager; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.EditorConfig; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.EditorConfig; import org.jetbrains.annotations.NotNull; import java.io.IOException; diff --git a/src/main/java/com/ss/editor/control/brush/BrushControl.java b/src/main/java/com/ss/builder/jme/control/brush/BrushControl.java similarity index 79% rename from src/main/java/com/ss/editor/control/brush/BrushControl.java rename to src/main/java/com/ss/builder/jme/control/brush/BrushControl.java index 7c6e2b85..e588ed52 100644 --- a/src/main/java/com/ss/editor/control/brush/BrushControl.java +++ b/src/main/java/com/ss/builder/jme/control/brush/BrushControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.brush; +package com.ss.builder.jme.control.brush; import com.jme3.scene.control.Control; diff --git a/src/main/java/com/ss/builder/jme/control/brush/editor/scene/SceneEditorBrushControl.java b/src/main/java/com/ss/builder/jme/control/brush/editor/scene/SceneEditorBrushControl.java new file mode 100644 index 00000000..ee813bae --- /dev/null +++ b/src/main/java/com/ss/builder/jme/control/brush/editor/scene/SceneEditorBrushControl.java @@ -0,0 +1,11 @@ +package com.ss.builder.jme.control.brush.editor.scene; + +import com.ss.builder.jme.control.brush.BrushControl; + +/** + * The interface to implement a brush in a scene editor. + * + * @author JavaSaBr + */ +public interface SceneEditorBrushControl extends BrushControl { +} diff --git a/src/main/java/com/ss/editor/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java b/src/main/java/com/ss/builder/jme/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java similarity index 80% rename from src/main/java/com/ss/editor/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java rename to src/main/java/com/ss/builder/jme/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java index dc6daa6f..e24d24c3 100644 --- a/src/main/java/com/ss/editor/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java +++ b/src/main/java/com/ss/builder/jme/control/brush/editor/scene/impl/AbstractSceneEditorBrushControl.java @@ -1,9 +1,9 @@ -package com.ss.editor.control.brush.editor.scene.impl; +package com.ss.builder.jme.control.brush.editor.scene.impl; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.scene.control.AbstractControl; -import com.ss.editor.control.brush.editor.scene.SceneEditorBrushControl; +import com.ss.builder.jme.control.brush.editor.scene.SceneEditorBrushControl; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/editor/control/painting/PaintingControl.java b/src/main/java/com/ss/builder/jme/control/painting/PaintingControl.java similarity index 94% rename from src/main/java/com/ss/editor/control/painting/PaintingControl.java rename to src/main/java/com/ss/builder/jme/control/painting/PaintingControl.java index 94ed3fd4..85b7c842 100644 --- a/src/main/java/com/ss/editor/control/painting/PaintingControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/PaintingControl.java @@ -1,9 +1,10 @@ -package com.ss.editor.control.painting; +package com.ss.builder.jme.control.painting; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/control/painting/PaintingInput.java b/src/main/java/com/ss/builder/jme/control/painting/PaintingInput.java similarity index 88% rename from src/main/java/com/ss/editor/control/painting/PaintingInput.java rename to src/main/java/com/ss/builder/jme/control/painting/PaintingInput.java index 0dfae8c3..2fdd21da 100644 --- a/src/main/java/com/ss/editor/control/painting/PaintingInput.java +++ b/src/main/java/com/ss/builder/jme/control/painting/PaintingInput.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.painting; +package com.ss.builder.jme.control.painting; /** * The enum with list of painting inputs. diff --git a/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java b/src/main/java/com/ss/builder/jme/control/painting/impl/AbstractPaintingControl.java similarity index 90% rename from src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java rename to src/main/java/com/ss/builder/jme/control/painting/impl/AbstractPaintingControl.java index 9158868b..5723e5f2 100644 --- a/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/impl/AbstractPaintingControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.painting.impl; +package com.ss.builder.jme.control.painting.impl; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; @@ -11,13 +11,15 @@ import com.jme3.scene.Spatial; import com.jme3.scene.control.AbstractControl; import com.jme3.scene.shape.Sphere; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingControl; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.PaintingComponent; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingControl; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.fx.component.painting.PaintingComponent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -170,7 +172,7 @@ public void setSpatial(@Nullable final Spatial spatial) { */ @JmeThread protected @NotNull Material createColoredMaterial(@NotNull final ColorRGBA color) { - final Material material = new Material(EditorUtil.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + final Material material = new Material(EditorUtils.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); material.setColor("Color", color); return material; } diff --git a/src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/spawn/SpawnToolControl.java similarity index 94% rename from src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/spawn/SpawnToolControl.java index 59c08db2..861f5700 100644 --- a/src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/spawn/SpawnToolControl.java @@ -1,7 +1,7 @@ -package com.ss.editor.control.painting.spawn; +package com.ss.builder.jme.control.painting.spawn; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_IGNORE_RAY_CAST; -import static com.ss.editor.util.EditorUtil.getAssetManager; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_IGNORE_RAY_CAST; +import static com.ss.builder.util.EditorUtils.getAssetManager; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; import com.jme3.asset.ModelKey; @@ -15,16 +15,18 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.terrain.Terrain; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.control.painting.impl.AbstractPaintingControl; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.component.painting.spawn.SpawnPaintingComponent; -import com.ss.editor.util.GeomUtils; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.jme.control.painting.impl.AbstractPaintingControl; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AddChildOperation; +import com.ss.builder.fx.component.painting.spawn.SpawnPaintingComponent; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import jme3tools.optimize.GeometryBatchFactory; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/ChangeHeightTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/ChangeHeightTerrainToolControl.java similarity index 93% rename from src/main/java/com/ss/editor/control/painting/terrain/ChangeHeightTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/ChangeHeightTerrainToolControl.java index 578c125f..123146c6 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/ChangeHeightTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/ChangeHeightTerrainToolControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.math.Vector2f; @@ -6,13 +6,15 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.terrain.Terrain; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import com.ss.rlib.common.util.dictionary.Dictionary; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/LevelTerrainToolControl.java similarity index 95% rename from src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/LevelTerrainToolControl.java index c8d1b346..30cbf3fb 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/LevelTerrainToolControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; -import static com.ss.editor.util.PaintingUtils.isContains; +import static com.ss.builder.util.PaintingUtils.isContains; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; @@ -10,11 +10,13 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial.CullHint; import com.jme3.scene.shape.Sphere; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.util.PaintingUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.util.PaintingUtils; import com.ss.rlib.common.util.ExtMath; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/PaintTerrainToolControl.java similarity index 95% rename from src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/PaintTerrainToolControl.java index b0190ba6..116ccf09 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/PaintTerrainToolControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; @@ -10,14 +10,16 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.util.BufferUtils; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.fx.control.property.operation.PropertyOperation; +import com.ss.builder.util.LocalObjects; import com.ss.rlib.common.function.ObjectFloatObjectConsumer; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -241,14 +243,15 @@ private void startChange() { @JmeThread protected void change(final int index, @NotNull final ColorRGBA color) { - final Array colorPoints = getColorPoints(); - final ColorPoint search = colorPoints.search(index, (point, toCheck) -> point.index == toCheck); + var colorPoints = getColorPoints(); + var colorPoint = colorPoints.findAny(index, + (point, toCheck) -> point.index == toCheck); - if (search != null) { - search.red = color.r; - search.green = color.g; - search.blue = color.b; - search.alpha = color.a; + if (colorPoint != null) { + colorPoint.red = color.r; + colorPoint.green = color.g; + colorPoint.blue = color.b; + colorPoint.alpha = color.a; return; } diff --git a/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/RaiseLowerTerrainToolControl.java similarity index 92% rename from src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/RaiseLowerTerrainToolControl.java index 80af451a..d7102ff7 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/RaiseLowerTerrainToolControl.java @@ -1,7 +1,7 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; -import static com.ss.editor.util.PaintingUtils.calculateHeight; -import static com.ss.editor.util.PaintingUtils.isContains; +import static com.ss.builder.util.PaintingUtils.calculateHeight; +import static com.ss.builder.util.PaintingUtils.isContains; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; @@ -11,11 +11,11 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.terrain.Terrain; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/RoughTerrainToolControl.java similarity index 95% rename from src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/RoughTerrainToolControl.java index 76419d96..54714134 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/RoughTerrainToolControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; -import static com.ss.editor.util.PaintingUtils.isContains; +import static com.ss.builder.util.PaintingUtils.isContains; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.lang.Math.max; import static java.lang.Math.min; @@ -21,11 +21,13 @@ import com.jme3.terrain.noise.filter.SmoothFilter; import com.jme3.terrain.noise.fractal.FractalSum; import com.jme3.terrain.noise.modulator.NoiseModulator; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import java.nio.FloatBuffer; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/SlopeTerrainToolControl.java similarity index 96% rename from src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/SlopeTerrainToolControl.java index 64d35c4c..41124a34 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/SlopeTerrainToolControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; -import static com.ss.editor.util.PaintingUtils.isContains; +import static com.ss.builder.util.PaintingUtils.isContains; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.lang.Math.max; import com.jme3.math.ColorRGBA; @@ -11,11 +11,13 @@ import com.jme3.scene.Node; import com.jme3.scene.shape.Line; import com.jme3.scene.shape.Sphere; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.util.PaintingUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.util.PaintingUtils; import com.ss.rlib.common.util.ExtMath; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/SmoothTerrainToolControl.java similarity index 92% rename from src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java rename to src/main/java/com/ss/builder/jme/control/painting/terrain/SmoothTerrainToolControl.java index 9e801921..2b4268aa 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/SmoothTerrainToolControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.control.painting.terrain; +package com.ss.builder.jme.control.painting.terrain; -import static com.ss.editor.util.PaintingUtils.isContains; +import static com.ss.builder.util.PaintingUtils.isContains; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.lang.Float.isNaN; import static java.lang.Math.min; @@ -12,11 +12,13 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.terrain.Terrain; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/src/main/java/com/ss/builder/jme/control/painting/terrain/TerrainToolControl.java b/src/main/java/com/ss/builder/jme/control/painting/terrain/TerrainToolControl.java new file mode 100644 index 00000000..e18d1c3f --- /dev/null +++ b/src/main/java/com/ss/builder/jme/control/painting/terrain/TerrainToolControl.java @@ -0,0 +1,38 @@ +package com.ss.builder.jme.control.painting.terrain; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.fx.component.painting.terrain.TerrainPaintingComponent; +import com.ss.builder.jme.control.painting.impl.AbstractPaintingControl; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of terrain tool. + * + * @author JavaSaBr + */ +public class TerrainToolControl extends AbstractPaintingControl { + + public TerrainToolControl(@NotNull final TerrainPaintingComponent component) { + super(component); + } + + /** + * Get the change consumer. + * + * @return the change consumer. + */ + @FromAnyThread + protected @NotNull ModelChangeConsumer getChangeConsumer() { + return component.getChangeConsumer(); + } + + @Override + @JmeThread + public @Nullable Spatial getPaintedModel() { + return component.getPaintedObject(); + } +} diff --git a/src/main/java/com/ss/editor/control/transform/AbstractTransformControl.java b/src/main/java/com/ss/builder/jme/control/transform/AbstractTransformControl.java similarity index 93% rename from src/main/java/com/ss/editor/control/transform/AbstractTransformControl.java rename to src/main/java/com/ss/builder/jme/control/transform/AbstractTransformControl.java index 5e4ff4ee..1072c0c2 100644 --- a/src/main/java/com/ss/editor/control/transform/AbstractTransformControl.java +++ b/src/main/java/com/ss/builder/jme/control/transform/AbstractTransformControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.collision.CollisionResult; @@ -7,9 +7,11 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.control.AbstractControl; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.transform.EditorTransformSupport.PickedAxis; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.transform.EditorTransformSupport.PickedAxis; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/control/transform/EditorTransformSupport.java b/src/main/java/com/ss/builder/jme/control/transform/EditorTransformSupport.java similarity index 97% rename from src/main/java/com/ss/editor/control/transform/EditorTransformSupport.java rename to src/main/java/com/ss/builder/jme/control/transform/EditorTransformSupport.java index f0037ba9..ea0f8237 100644 --- a/src/main/java/com/ss/editor/control/transform/EditorTransformSupport.java +++ b/src/main/java/com/ss/builder/jme/control/transform/EditorTransformSupport.java @@ -1,15 +1,17 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; -import static com.ss.editor.util.GeomUtils.*; +import static com.ss.builder.util.GeomUtils.*; import com.jme3.math.Quaternion; import com.jme3.math.Transform; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -342,7 +344,7 @@ public void prepareToMove(@NotNull final Node parent, @NotNull final Node child, * @return the collision plane. */ @JmeThread - @Nullable Node getCollisionPlane(); + @NotNull Node getCollisionPlane(); /** * Set delta of transformation. diff --git a/src/main/java/com/ss/editor/control/transform/MoveToolControl.java b/src/main/java/com/ss/builder/jme/control/transform/MoveToolControl.java similarity index 94% rename from src/main/java/com/ss/editor/control/transform/MoveToolControl.java rename to src/main/java/com/ss/builder/jme/control/transform/MoveToolControl.java index cdcb3f2c..92976dfc 100644 --- a/src/main/java/com/ss/editor/control/transform/MoveToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/transform/MoveToolControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; -import static com.ss.editor.util.GeomUtils.*; +import static com.ss.builder.util.GeomUtils.*; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.collision.CollisionResult; import com.jme3.collision.CollisionResults; @@ -11,13 +11,15 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.Config; -import com.ss.editor.control.transform.EditorTransformSupport.PickedAxis; -import com.ss.editor.control.transform.EditorTransformSupport.TransformationMode; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.Config; +import com.ss.builder.jme.control.transform.EditorTransformSupport.PickedAxis; +import com.ss.builder.jme.control.transform.EditorTransformSupport.TransformationMode; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; /** @@ -167,7 +169,7 @@ public void processTransform() { final LocalObjects local = LocalObjects.get(); final Camera camera = editorControl.getCamera(); - final InputManager inputManager = EditorUtil.getInputManager(); + final InputManager inputManager = EditorUtils.getInputManager(); final Vector2f cursorPosition = inputManager.getCursorPosition(); final CollisionResults results = local.nextCollisionResults(); diff --git a/src/main/java/com/ss/editor/control/transform/RotationToolControl.java b/src/main/java/com/ss/builder/jme/control/transform/RotationToolControl.java similarity index 89% rename from src/main/java/com/ss/editor/control/transform/RotationToolControl.java rename to src/main/java/com/ss/builder/jme/control/transform/RotationToolControl.java index eccba28d..4eb0e499 100644 --- a/src/main/java/com/ss/editor/control/transform/RotationToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/transform/RotationToolControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.input.InputManager; @@ -8,11 +8,13 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.transform.EditorTransformSupport.TransformationMode; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.transform.EditorTransformSupport.TransformationMode; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; /** @@ -59,7 +61,7 @@ public void processTransform() { final LocalObjects local = LocalObjects.get(); final EditorTransformSupport editorControl = getEditorControl(); - final InputManager inputManager = EditorUtil.getInputManager(); + final InputManager inputManager = EditorUtils.getInputManager(); final Camera camera = editorControl.getCamera(); final Transform transform = notNull(editorControl.getTransformCenter()); diff --git a/src/main/java/com/ss/editor/control/transform/ScaleToolControl.java b/src/main/java/com/ss/builder/jme/control/transform/ScaleToolControl.java similarity index 88% rename from src/main/java/com/ss/editor/control/transform/ScaleToolControl.java rename to src/main/java/com/ss/builder/jme/control/transform/ScaleToolControl.java index aa7fcae7..82b1d2f4 100644 --- a/src/main/java/com/ss/editor/control/transform/ScaleToolControl.java +++ b/src/main/java/com/ss/builder/jme/control/transform/ScaleToolControl.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static java.lang.Math.abs; @@ -11,12 +11,14 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.Config; -import com.ss.editor.control.transform.EditorTransformSupport.TransformationMode; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.Config; +import com.ss.builder.jme.control.transform.EditorTransformSupport.TransformationMode; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; /** @@ -73,7 +75,7 @@ public void processTransform() { final LocalObjects local = LocalObjects.get(); final Camera camera = editorControl.getCamera(); - final InputManager inputManager = EditorUtil.getInputManager(); + final InputManager inputManager = EditorUtils.getInputManager(); final Transform transform = notNull(editorControl.getTransformCenter()); // cursor position and selected position vectors @@ -92,7 +94,7 @@ public void processTransform() { // Picked vector final Spatial toTransform = notNull(editorControl.getToTransform()); - final TransformationMode transformationMode = editorControl.getTransformationMode(); + final EditorTransformSupport.TransformationMode transformationMode = editorControl.getTransformationMode(); transformationMode.prepareToScale(parentNode, childNode, transform, camera); // scale according to distance diff --git a/src/main/java/com/ss/editor/control/transform/TransformConstraint.java b/src/main/java/com/ss/builder/jme/control/transform/TransformConstraint.java similarity index 95% rename from src/main/java/com/ss/editor/control/transform/TransformConstraint.java rename to src/main/java/com/ss/builder/jme/control/transform/TransformConstraint.java index 6542c5e0..8b399fd6 100644 --- a/src/main/java/com/ss/editor/control/transform/TransformConstraint.java +++ b/src/main/java/com/ss/builder/jme/control/transform/TransformConstraint.java @@ -1,4 +1,4 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; /** * The type Transform constraint. diff --git a/src/main/java/com/ss/editor/control/transform/TransformControl.java b/src/main/java/com/ss/builder/jme/control/transform/TransformControl.java similarity index 80% rename from src/main/java/com/ss/editor/control/transform/TransformControl.java rename to src/main/java/com/ss/builder/jme/control/transform/TransformControl.java index d356de15..49993249 100644 --- a/src/main/java/com/ss/editor/control/transform/TransformControl.java +++ b/src/main/java/com/ss/builder/jme/control/transform/TransformControl.java @@ -1,9 +1,10 @@ -package com.ss.editor.control.transform; +package com.ss.builder.jme.control.transform; import com.jme3.collision.CollisionResult; import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/EditableSceneEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/EditableSceneEditor3dPart.java new file mode 100644 index 00000000..40cb676d --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/EditableSceneEditor3dPart.java @@ -0,0 +1,23 @@ +package com.ss.builder.jme.editor.part3d; + +import com.jme3.scene.Node; +import com.ss.builder.annotation.JmeThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to mark an editor 3d part that it supports editing a 3d scene. + * + * @author JavaSaBr + */ +public interface EditableSceneEditor3dPart extends Editor3dPart { + + String PROP_IS_EDITING = "EditableSceneEditor3dPart.isEditing"; + + /** + * Get a tool node. + * + * @return the tool node. + */ + @JmeThread + @NotNull Node getToolNode(); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/Editor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/Editor3dPart.java new file mode 100644 index 00000000..501b087c --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/Editor3dPart.java @@ -0,0 +1,12 @@ +package com.ss.builder.jme.editor.part3d; + +import com.jme3.app.state.AppState; + +/** + * The interface to implement a 3d part of editor. + * + * @author JavaSaBr + */ +public interface Editor3dPart extends AppState { + +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/ExtendableEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/ExtendableEditor3dPart.java new file mode 100644 index 00000000..9ddea36b --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/ExtendableEditor3dPart.java @@ -0,0 +1,84 @@ +package com.ss.builder.jme.editor.part3d; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; + +import com.jme3.renderer.Camera; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.Editor3dPartControl; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.editor.FileEditor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The extendable 3d part of editor. + * + * @author JavaSaBr + */ +public interface ExtendableEditor3dPart extends Editor3dPart { + + /** + * Get the root node of this part. + * + * @return the root node of this part. + */ + @FromAnyThread + @NotNull Node getRootNode(); + + /** + * Get a presented camera in this editor 3d part. + * + * @return the presented camera in this editor 3d part. + */ + @FromAnyThread + @NotNull Camera getCamera(); + + /** + * Get the file editor. + * + * @return the file editor. + */ + @FromAnyThread + @NotNull FileEditor getFileEditor(); + + /** + * Get a control by the type. + * + * @param type the control's type. + * @param the control's type. + * @return the control or null. + */ + @FromAnyThread + @Nullable C getControl(@NotNull Class type); + + /** + * Get a control by the type. + * + * @param type the control's type. + * @param the control's type. + * @return the control. + */ + @FromAnyThread + default @NotNull C requireControl(@NotNull Class type) { + return notNull(getControl(type)); + } + + /** + * Get a boolean property value. + * + * @param propertyId the property id. + * @return the property value or false if the property is not known. + */ + @FromAnyThread + boolean getBooleanProperty(@NotNull String propertyId); + + /** + * Notify this 3d part about some events. + * + * @param event the event. + */ + @JmeThread + void notify(@NotNull Editor3dPartEvent event); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/SavableEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/SavableEditor3dPart.java new file mode 100644 index 00000000..819c5578 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/SavableEditor3dPart.java @@ -0,0 +1,29 @@ +package com.ss.builder.jme.editor.part3d; + +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.editor.FileEditor; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +/** + * The interface to mark an editor 3d part that it supports a save method. + * + * @author JavaSaBr + */ +public interface SavableEditor3dPart extends Editor3dPart { + + /** + * Save changes. + */ + @JmeThread + @NotNull CompletableFuture save(); + + /** + * Return true if this editor part has unsaved changes. + * + * @return true if this editor part has unsaved changes. + */ + @JmeThread + boolean isDirty(); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/UndoableEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/UndoableEditor3dPart.java new file mode 100644 index 00000000..be7950a7 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/UndoableEditor3dPart.java @@ -0,0 +1,24 @@ +package com.ss.builder.jme.editor.part3d; + +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; + +/** + * The interface to mark an editor 3d part that it supports undo/redo methods. + * + * @author JavaSaBr + */ +public interface UndoableEditor3dPart extends Editor3dPart { + + /** + * Undo the previous operation. + */ + @JmeThread + void undo(); + + /** + * Redo the last operation. + */ + @JmeThread + void redo(); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/Editor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/Editor3dPartControl.java new file mode 100644 index 00000000..ca53d3e9 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/Editor3dPartControl.java @@ -0,0 +1,79 @@ +package com.ss.builder.jme.editor.part3d.control; + +import com.jme3.app.Application; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import org.jetbrains.annotations.NotNull; + +/** + * Interface to implement an additional control for {@link Editor3dPart}. + * + * @author JavaSaBr + */ +public interface Editor3dPartControl { + + /** + * Initialize the control during initializing parent 3d part. + * + * @param application the application. + */ + @JmeThread + void initialize(@NotNull Application application); + + /** + * Cleanup this control during cleaning the parent 3d part. + * + * @param application the application. + */ + @JmeThread + void cleanup(@NotNull Application application); + + @JmeThread + default void update(float tpf) { + } + + @JmeThread + default void preCameraUpdate(float tpf) { + } + + @JmeThread + default void cameraUpdate(float tpf) { + } + + @JmeThread + default void postCameraUpdate(float tpf) { + } + + /** + * Return true if this control knows about the property. + * + * @param propertyId the property id. + * @return true if this control knows about the property. + */ + @JmeThread + default boolean hasProperty(@NotNull String propertyId) { + return false; + } + + /** + * Get a boolean property value. + * + * @param propertyId the property id. + * @return the property value or false if the property is not known. + */ + @JmeThread + default boolean getBooleanProperty(@NotNull String propertyId) { + return false; + } + + /** + * Notify this 3d part control about some events. + * + * @param event the event. + */ + @JmeThread + void notify(@NotNull Editor3dPartEvent event); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/InputEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/InputEditor3dPartControl.java new file mode 100644 index 00000000..04c76dc3 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/InputEditor3dPartControl.java @@ -0,0 +1,81 @@ +package com.ss.builder.jme.editor.part3d.control; + +import com.jme3.app.Application; +import com.jme3.input.InputManager; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement a control which works with input system of editor 3d part. + * + * @author JavaSaBr + */ +public interface InputEditor3dPartControl extends Editor3dPartControl { + + @Override + @JmeThread + default void initialize(@NotNull Application application) { + register(application.getInputManager()); + } + + @Override + @JmeThread + default void cleanup(@NotNull Application application) { + unregister(application.getInputManager()); + } + + /** + * Register interested mappings and listeners. + * + * @param inputManager the input manager. + */ + @JmeThread + void register(@NotNull InputManager inputManager); + + /** + * Unregister listeners. + * + * @param inputManager the input manager. + */ + @JmeThread + default void unregister(@NotNull InputManager inputManager) { + inputManager.removeListener(getActionListener()); + inputManager.removeListener(getAnalogListener()); + } + + /** + * Get the action listener. + * + * @return the action listener. + */ + @FromAnyThread + @NotNull ActionListener getActionListener(); + + /** + * Get the analog listener. + * + * @return the analog listener. + */ + @FromAnyThread + @NotNull AnalogListener getAnalogListener(); + + /** + * @see ActionListener#onAction(String, boolean, float) + */ + @JmeThread + default void onAction(@NotNull String name, boolean isPressed, float tpf) { + } + + /** + * @see AnalogListener#onAnalog(String, float, float) + */ + @JmeThread + default void onAnalog(@NotNull String name, float value, float tpf) { + + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractEditor3dPartControl.java new file mode 100644 index 00000000..b9184ffb --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractEditor3dPartControl.java @@ -0,0 +1,49 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.Editor3dPartControl; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.Editor3dPartControl; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of {@link Editor3dPartControl}. + * + * @author JavaSaBr + */ +public abstract class AbstractEditor3dPartControl implements Editor3dPartControl { + + protected static final Logger LOGGER = LoggerManager.getLogger(Editor3dPartControl.class); + + /** + * The editor's 3d part. + */ + @NotNull + protected final E editor3dPart; + + protected AbstractEditor3dPartControl(@NotNull E editor3dPart) { + this.editor3dPart = editor3dPart; + } + + @Override + @JmeThread + public void notify(@NotNull Editor3dPartEvent event) { + if (event.getSource() != this) { + notifyImpl(event); + } + } + + /** + * Notify this 3d part about some events. + * + * @param event the event. + */ + @JmeThread + protected void notifyImpl(@NotNull Editor3dPartEvent event) { + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractSceneEditorHotKeys3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractSceneEditorHotKeys3dPartControl.java new file mode 100644 index 00000000..ac220309 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/AbstractSceneEditorHotKeys3dPartControl.java @@ -0,0 +1,43 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import com.jme3.input.KeyInput; +import com.jme3.input.controls.KeyTrigger; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * The input control of {@link BaseMaterialEditor3dPart} + * + * @author JavaSaBr + */ +public class AbstractSceneEditorHotKeys3dPartControl extends KeyEventRedirectEditor3dPartControl { + + private static final String KEY_S = "jMB.abstractSceneEditorHotKeys.S"; + private static final String KEY_G = "jMB.abstractSceneEditorHotKeys.G"; + private static final String KEY_R = "jMB.abstractSceneEditorHotKeys.R"; + private static final String KEY_DEL = "jMB.abstractSceneEditorHotKeys.Del"; + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, KeyTrigger.class); + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(KEY_G, new KeyTrigger(KeyInput.KEY_G)); + TRIGGERS.put(KEY_S, new KeyTrigger(KeyInput.KEY_S)); + TRIGGERS.put(KEY_R, new KeyTrigger(KeyInput.KEY_R)); + TRIGGERS.put(KEY_DEL, new KeyTrigger(KeyInput.KEY_DELETE)); + + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + public AbstractSceneEditorHotKeys3dPartControl(@NotNull ExtendableEditor3dPart editor3dPart) { + super(editor3dPart, TRIGGERS, MAPPINGS); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseHotKeysEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseHotKeysEditor3dPartControl.java new file mode 100644 index 00000000..70509f2c --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseHotKeysEditor3dPartControl.java @@ -0,0 +1,74 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import static com.ss.builder.jme.editor.part3d.control.impl.InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN; +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.Trigger; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.SavableEditor3dPart; +import com.ss.builder.jme.editor.part3d.UndoableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * The control to base hotkeys of the editor 3d part. + * + * @author JavaSaBr + */ +public class BaseHotKeysEditor3dPartControl + extends BaseInputEditor3dPartControl { + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final String KEY_CTRL_S = "jMB.baseHotKeysEditor.Ctrl.S"; + private static final String KEY_CTRL_Z = "jMB.baseHotKeysEditor.Ctrl.Z"; + private static final String KEY_CTRL_Y = "jMB.baseHotKeysEditor.Ctrl.Y"; + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(KEY_CTRL_S, new KeyTrigger(KeyInput.KEY_S)); + TRIGGERS.put(KEY_CTRL_Z, new KeyTrigger(KeyInput.KEY_Z)); + TRIGGERS.put(KEY_CTRL_Y, new KeyTrigger(KeyInput.KEY_Y)); + + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + public BaseHotKeysEditor3dPartControl(@NotNull T editor3dPart) { + super(editor3dPart); + + actionHandlers.put(KEY_CTRL_Z, (isPressed, tpf) -> { + if (!isPressed && editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN)) { + editor3dPart.undo(); + } + }); + + actionHandlers.put(KEY_CTRL_Y, (isPressed, tpf) -> { + if (!isPressed && editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN)) { + editor3dPart.redo(); + } + }); + + actionHandlers.put(KEY_CTRL_S, (isPressed, tpf) -> { + if (isPressed && editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN) && editor3dPart.isDirty()) { + editor3dPart.save(); + } + }); + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + inputManager.addListener(getActionListener(), MAPPINGS); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseInputEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseInputEditor3dPartControl.java new file mode 100644 index 00000000..f394244c --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/BaseInputEditor3dPartControl.java @@ -0,0 +1,94 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.InputEditor3dPartControl; +import com.ss.rlib.common.function.BooleanFloatConsumer; +import com.ss.rlib.common.function.FloatFloatConsumer; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * Base implementation of editor control which works with input system. + * + * @param the editor 3d part's type. + * @author JavaSaBr + */ +public abstract class BaseInputEditor3dPartControl extends + AbstractEditor3dPartControl implements InputEditor3dPartControl { + + /** + * The table of action handlers. + */ + @NotNull + protected final ObjectDictionary actionHandlers; + + /** + * The table of analog handlers. + */ + @NotNull + protected final ObjectDictionary analogHandlers; + + /** + * The action listener. + */ + @NotNull + private final ActionListener actionListener; + + /** + * The analog listener. + */ + @NotNull + private final AnalogListener analogListener; + + protected BaseInputEditor3dPartControl(@NotNull T editor3dPart) { + super(editor3dPart); + this.actionHandlers = ObjectDictionary.ofType(String.class, BooleanFloatConsumer.class); + this.analogHandlers = ObjectDictionary.ofType(String.class, FloatFloatConsumer.class); + this.actionListener = this::onAction; + this.analogListener = this::onAnalog; + } + + @Override + @FromAnyThread + public @NotNull ActionListener getActionListener() { + return actionListener; + } + + @Override + @FromAnyThread + public @NotNull AnalogListener getAnalogListener() { + return analogListener; + } + + @Override + @JmeThread + public void onAction(@NotNull String name, boolean isPressed, float tpf) { + + var handler = actionHandlers.get(name); + + if (handler == null) { + LOGGER.warning(this, "Unknown action " + name); + return; + } + + handler.accept(isPressed, tpf); + } + + @Override + @JmeThread + public void onAnalog(@NotNull String name, float value, float tpf) { + + var handler = analogHandlers.get(name); + + if (handler == null) { + LOGGER.warning(this, "Unknown analog " + name); + return; + } + + handler.accept(value, tpf); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/CameraEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/CameraEditor3dPartControl.java new file mode 100644 index 00000000..75c16cb5 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/CameraEditor3dPartControl.java @@ -0,0 +1,796 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import static com.ss.rlib.common.util.array.ArrayFactory.toArray; +import com.jme3.app.Application; +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.*; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.editor.event.CameraChangedFileEditorEvent; +import com.ss.builder.config.Config; +import com.ss.builder.jme.editor.part3d.control.InputEditor3dPartControl; +import com.ss.builder.model.EditorCamera; +import com.ss.builder.model.EditorCamera.Direction; +import com.ss.builder.model.EditorCamera.Perspective; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.rlib.common.function.FloatConsumer; +import com.ss.rlib.common.logging.LoggerLevel; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The editor's camera control. + * + * @author JavaSaBr + */ +public class CameraEditor3dPartControl extends BaseInputEditor3dPartControl implements + InputEditor3dPartControl, ActionListener, AnalogListener { + + public static class CameraState implements Serializable { + + @NotNull Vector3f cameraLocation; + + float hRotation; + float vRotation; + float targetDistance; + float cameraFlySpeed; + + public CameraState() { + this.cameraLocation = new Vector3f(); + } + + public CameraState( + @NotNull Vector3f cameraLocation, + float hRotation, + float vRotation, + float targetDistance, + float cameraFlySpeed + ) { + this.cameraLocation = cameraLocation; + this.hRotation = hRotation; + this.vRotation = vRotation; + this.targetDistance = targetDistance; + this.cameraFlySpeed = cameraFlySpeed; + } + + @FromAnyThread + public float getCameraFlySpeed() { + return cameraFlySpeed; + } + + @FromAnyThread + public @NotNull Vector3f getCameraLocation() { + return cameraLocation; + } + + @FromAnyThread + public float getHRotation() { + return hRotation; + } + + @FromAnyThread + public float getVRotation() { + return vRotation; + } + + @FromAnyThread + public float getTargetDistance() { + return targetDistance; + } + } + + private enum KeyState { + KEY_A, + KEY_D, + KEY_W, + KEY_S, + KEY_ANY + } + + private static final ObjectDictionary ACTION_TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final ObjectDictionary ANALOG_TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final ObjectDictionary ACTION_MULTI_TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger[].class); + + private static final String MOUSE_RIGHT_CLICK = "jMB.editorCamera.rightClick"; + private static final String MOUSE_LEFT_CLICK = "jMB.editorCamera.leftClick"; + private static final String MOUSE_MIDDLE_CLICK = "jMB.editorCamera.middleClick"; + + private static final String MOUSE_X_AXIS = "jMB.editorCamera.mouseXAxis"; + private static final String MOUSE_X_AXIS_NEGATIVE = "jMB.editorCamera.mouseXAxisNegative"; + private static final String MOUSE_Y_AXIS = "jMB.baseEditor.editorCamera"; + private static final String MOUSE_Y_AXIS_NEGATIVE = "jMB.editorCamera.mouseYAxisNegative"; + + private static final String KEY_W = "jMB.editorCamera.W"; + private static final String KEY_S = "jMB.editorCamera.S"; + private static final String KEY_A = "jMB.editorCamera.A"; + private static final String KEY_D = "jMB.editorCamera.D"; + private static final String KEY_ALT = "jMB.editorCamera.Alt"; + private static final String KEY_CTRL = "jMB.editorCamera.Ctrl"; + private static final String KEY_SHIFT = "jMB.editorCamera.Shift"; + + private static final String KEY_NUM_1 = "jMB.editorCamera.num1"; + private static final String KEY_NUM_2 = "jMB.editorCamera.num2"; + private static final String KEY_NUM_3 = "jMB.editorCamera.num3"; + private static final String KEY_NUM_4 = "jMB.editorCamera.num4"; + private static final String KEY_NUM_6 = "jMB.editorCamera.num6"; + private static final String KEY_NUM_7 = "jMB.editorCamera.num7"; + private static final String KEY_NUM_8 = "jMB.editorCamera.num8"; + private static final String KEY_NUM_9 = "jMB.editorCamera.num9"; + + private static final String[] ACTION_MAPPINGS; + private static final String[] ANALOG_MAPPINGS; + + static { + + ACTION_TRIGGERS.put(MOUSE_RIGHT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + ACTION_TRIGGERS.put(MOUSE_LEFT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + ACTION_TRIGGERS.put(MOUSE_MIDDLE_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); + + ACTION_TRIGGERS.put(KEY_W, new KeyTrigger(KeyInput.KEY_W)); + ACTION_TRIGGERS.put(KEY_S, new KeyTrigger(KeyInput.KEY_S)); + ACTION_TRIGGERS.put(KEY_A, new KeyTrigger(KeyInput.KEY_A)); + ACTION_TRIGGERS.put(KEY_D, new KeyTrigger(KeyInput.KEY_D)); + + ACTION_TRIGGERS.put(KEY_NUM_1, new KeyTrigger(KeyInput.KEY_NUMPAD1)); + ACTION_TRIGGERS.put(KEY_NUM_2, new KeyTrigger(KeyInput.KEY_NUMPAD2)); + ACTION_TRIGGERS.put(KEY_NUM_3, new KeyTrigger(KeyInput.KEY_NUMPAD3)); + ACTION_TRIGGERS.put(KEY_NUM_4, new KeyTrigger(KeyInput.KEY_NUMPAD4)); + ACTION_TRIGGERS.put(KEY_NUM_6, new KeyTrigger(KeyInput.KEY_NUMPAD6)); + ACTION_TRIGGERS.put(KEY_NUM_7, new KeyTrigger(KeyInput.KEY_NUMPAD7)); + ACTION_TRIGGERS.put(KEY_NUM_8, new KeyTrigger(KeyInput.KEY_NUMPAD8)); + ACTION_TRIGGERS.put(KEY_NUM_9, new KeyTrigger(KeyInput.KEY_NUMPAD9)); + + ACTION_MULTI_TRIGGERS.put(KEY_CTRL, toArray(new KeyTrigger(KeyInput.KEY_RCONTROL), new KeyTrigger(KeyInput.KEY_LCONTROL))); + ACTION_MULTI_TRIGGERS.put(KEY_ALT, toArray(new KeyTrigger(KeyInput.KEY_RMENU), new KeyTrigger(KeyInput.KEY_LMENU))); + ACTION_MULTI_TRIGGERS.put(KEY_SHIFT, toArray(new KeyTrigger(KeyInput.KEY_RSHIFT), new KeyTrigger(KeyInput.KEY_LSHIFT))); + + ANALOG_TRIGGERS.put(MOUSE_X_AXIS, new MouseAxisTrigger(MouseInput.AXIS_X, false)); + ANALOG_TRIGGERS.put(MOUSE_X_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_X, true)); + ANALOG_TRIGGERS.put(MOUSE_Y_AXIS, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); + ANALOG_TRIGGERS.put(MOUSE_Y_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); + + Array mappings = ACTION_TRIGGERS.keyArray(String.class); + mappings.addAll(ACTION_MULTI_TRIGGERS.keyArray(String.class)); + + ACTION_MAPPINGS = mappings.toArray(String.class); + ANALOG_MAPPINGS = ANALOG_TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + /** + * The executor manager. + */ + @NotNull + private final ExecutorManager executorManager; + + /** + * The editor camera. + */ + @NotNull + private final EditorCamera editorCamera; + + /** + * The light of the camera. + */ + @NotNull + private final DirectionalLight light; + + /** + * The node on which the camera is looking. + */ + @NotNull + private final Node cameraNode; + + /** + * The flag of flying camera. + */ + @NotNull + private final AtomicInteger cameraFlying; + + /** + * The state of camera keys. + */ + @NotNull + private final boolean[] keyStates; + + /** + * The key state handlers. + */ + @NotNull + private final FloatConsumer[] keyStateHandlers; + + /** + * The previous state of the camera. + */ + @NotNull + private final CameraState prevState; + + /** + * The camera fly speed. + */ + private float cameraFlySpeed; + + /** + * The saved target distance. + */ + private float savedTargetDistance; + + /** + * True of need to add light for the camera. + */ + private boolean needLight; + + /** + * True if need to update light to follow the camera. + */ + private boolean needUpdateLight; + + /** + * TRue if need to allow the camera to be moved. + */ + private boolean needMovableCamera; + + public CameraEditor3dPartControl(@NotNull ExtendableEditor3dPart editor3dPart) { + this(editor3dPart, true, true, true); + } + + public CameraEditor3dPartControl( + @NotNull ExtendableEditor3dPart editor3dPart, + boolean needLight, + boolean needUpdateLight, + boolean needMovableCamera + ) { + super(editor3dPart); + this.executorManager = ExecutorManager.getInstance(); + this.cameraFlying = new AtomicInteger(); + this.keyStates = new boolean[4]; + this.keyStateHandlers = new FloatConsumer[4]; + this.cameraFlySpeed = 1F; + this.cameraNode = new Node("CameraNode"); + this.editorCamera = createEditorCamera(editor3dPart.getCamera()); + this.light = createLight(); + this.needLight = needLight; + this.needUpdateLight = needUpdateLight; + this.needMovableCamera = needMovableCamera; + this.prevState = new CameraState(); + + actionHandlers.put(KEY_NUM_1, (isPressed, tpf) -> rotateTo(Perspective.BACK, isPressed)); + actionHandlers.put(KEY_NUM_3, (isPressed, tpf) -> rotateTo(Perspective.RIGHT, isPressed)); + actionHandlers.put(KEY_NUM_7, (isPressed, tpf) -> rotateTo(Perspective.TOP, isPressed)); + actionHandlers.put(KEY_NUM_9, (isPressed, tpf) -> rotateTo(Perspective.BOTTOM, isPressed)); + actionHandlers.put(KEY_NUM_2, (isPressed, tpf) -> rotateTo(Direction.BOTTOM, isPressed)); + actionHandlers.put(KEY_NUM_8, (isPressed, tpf) -> rotateTo(Direction.TOP, isPressed)); + actionHandlers.put(KEY_NUM_4, (isPressed, tpf) -> rotateTo(Direction.LEFT, isPressed)); + actionHandlers.put(KEY_NUM_6, (isPressed, tpf) -> rotateTo(Direction.RIGHT, isPressed)); + actionHandlers.put(KEY_SHIFT, (isPressed, tpf) -> editorCamera.setLockRotation(isPressed)); + + actionHandlers.put(MOUSE_MIDDLE_CLICK, (isPressed, tpf) -> { + if (isCameraFlying() && !isPressed) { + finishCameraMoving(KeyState.KEY_ANY, true); + } + }); + + actionHandlers.put(KEY_CTRL, (isPressed, tpf) -> { + if (isCameraFlying() && isPressed && cameraFlySpeed > 0) { + cameraFlySpeed = Math.max(cameraFlySpeed - 0.4F, 0.1F); + } + }); + + actionHandlers.put(KEY_ALT, (isPressed, tpf) -> { + if (isCameraFlying() && isPressed && cameraFlySpeed > 0) { + cameraFlySpeed += 0.4F; + } + }); + + actionHandlers.put(KEY_A, (isPressed, tpf) -> + flyCameraSide(tpf, true, isPressed, KeyState.KEY_A)); + actionHandlers.put(KEY_D, (isPressed, tpf) -> + flyCameraSide(-tpf, true, isPressed, KeyState.KEY_D)); + actionHandlers.put(KEY_W, (isPressed, tpf) -> + flyCameraForward(tpf, true, isPressed, KeyState.KEY_W)); + actionHandlers.put(KEY_S, (isPressed, tpf) -> + flyCameraForward(-tpf, true, isPressed, KeyState.KEY_S)); + + analogHandlers.put(MOUSE_X_AXIS, (value, tpf) -> moveCameraHorizontal(value)); + analogHandlers.put(MOUSE_X_AXIS_NEGATIVE, (value, tpf) -> moveCameraHorizontal(-value)); + analogHandlers.put(MOUSE_Y_AXIS, (value, tpf) -> moveCameraVertical(-value)); + analogHandlers.put(MOUSE_Y_AXIS_NEGATIVE, (value, tpf) -> moveCameraVertical(value)); + + keyStateHandlers[KeyState.KEY_A.ordinal()] = tpf -> + flyCameraSide(tpf * 30, false, false, KeyState.KEY_A); + keyStateHandlers[KeyState.KEY_D.ordinal()] = tpf -> + flyCameraSide(-tpf * 30, false, false, KeyState.KEY_D); + keyStateHandlers[KeyState.KEY_W.ordinal()] = tpf -> + flyCameraForward(tpf * 30, false, false, KeyState.KEY_W); + keyStateHandlers[KeyState.KEY_S.ordinal()] = tpf -> + flyCameraForward(-tpf * 30, false, false, KeyState.KEY_S); + } + + /** + * Create light for camera directional light. + * + * @return the light for the camera. + */ + @FromAnyThread + protected @NotNull DirectionalLight createLight() { + + var light = new DirectionalLight(); + light.setColor(ColorRGBA.White); + + return light; + } + + /** + * sets the default horizontal rotation in radian of the camera at start of the application + * + * @param angleInRad the angle in rad + */ + @FromAnyThread + public void setDefaultHorizontalRotation(float angleInRad) { + editorCamera.setDefaultHorizontalRotation(angleInRad); + } + + /** + * sets the default vertical rotation in radian of the camera at start of the application + * + * @param angleInRad the angle in rad + */ + @FromAnyThread + public void setDefaultVerticalRotation(float angleInRad) { + editorCamera.setDefaultVerticalRotation(angleInRad); + } + + /** + * Create an editor camera. + * + * @param camera the camera. + * @return the new editor camera. + */ + @FromAnyThread + protected @NotNull EditorCamera createEditorCamera(@NotNull Camera camera) { + + var editorCamera = new EditorCamera(camera, cameraNode); + editorCamera.setMaxDistance(10000); + editorCamera.setMinDistance(0.01F); + editorCamera.setZoomSensitivity(0.2F); + + return editorCamera; + } + + /** + * Set the light's direction. + * + * @param direction the light's direction. + */ + @FromAnyThread + public void setLightDirection(@NotNull Vector3f direction) { + this.light.setDirection(direction); + } + + @Override + @JmeThread + public void initialize(@NotNull Application application) { + super.initialize(application); + + var rootNode = editor3dPart.getRootNode(); + rootNode.attachChild(cameraNode); + + if (needLight) { + rootNode.addLight(light); + } + } + + @Override + @JmeThread + public void cleanup(@NotNull Application application) { + super.cleanup(application); + + var rootNode = editor3dPart.getRootNode(); + rootNode.detachChild(cameraNode); + + if (needLight) { + rootNode.removeLight(light); + } + } + + /** + * Enable camera's light. + */ + @JmeThread + public void enableLight() { + + if (needLight) { + return; + } + + editor3dPart.getRootNode() + .addLight(light); + + needLight = true; + } + + /** + * Disable camera's light. + */ + @JmeThread + public void disableLight() { + + if (!needLight) { + return; + } + + editor3dPart.getRootNode() + .removeLight(light); + + needLight = false; + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + + ACTION_TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + ACTION_MULTI_TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + ANALOG_TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + + inputManager.addListener(getActionListener(), ACTION_MAPPINGS); + inputManager.addListener(getAnalogListener(), ANALOG_MAPPINGS); + + editorCamera.registerInput(inputManager); + } + + @Override + @JmeThread + public void unregister(@NotNull InputManager inputManager) { + super.unregister(inputManager); + editorCamera.unregisterInput(inputManager); + } + + @Override + @JmeThread + public void cameraUpdate(float tpf) { + editorCamera.update(tpf); + + if (isCameraFlying()) { + for (int i = 0; i < keyStateHandlers.length; i++) { + if (keyStates[i]) { + keyStateHandlers[i].consume(tpf); + } + } + } + + checkCameraChanges(editorCamera); + } + + @Override + @JmeThread + public void postCameraUpdate(float tpf) { + if (needLight && needUpdateLight) { + light.setDirection(editorCamera.getDirection()); + } + } + + /** + * Rotate to the perspective. + * + * @param perspective the perspective. + * @param isPressed true if a key is pressed. + */ + @JmeThread + private void rotateTo(@NotNull Perspective perspective, boolean isPressed) { + if (isPressed) { + editorCamera.rotateTo(perspective); + } + } + + /** + * Rotate to the direction. + * + * @param direction the direction. + * @param isPressed true if a key is pressed. + */ + @JmeThread + private void rotateTo(@NotNull Direction direction, boolean isPressed) { + if (isPressed) { + editorCamera.rotateTo(direction, 10F); + } + } + + /** + * Return true if the camera is flying now. + * + * @return true if the camera is flying now. + */ + @JmeThread + public boolean isCameraFlying() { + return cameraFlying.get() != 0; + } + + /** + * Start to move the camera. + */ + @JmeThread + private void startCameraFlying(@NotNull KeyState key) { + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "start camera moving[" + cameraFlying + "] for key " + key); + } + + if (cameraFlying.get() == 0) { + + var camera = editor3dPart.getCamera(); + var location = camera.getLocation(); + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "init position: " + location + " of the camera."); + } + + cameraNode.setLocalTranslation(location); + savedTargetDistance = editorCamera.getTargetDistance(); + editorCamera.setTargetDistance(0.01F); + } + + if (!keyStates[key.ordinal()]) { + keyStates[key.ordinal()] = true; + cameraFlying.incrementAndGet(); + } + } + + + /** + * Finish to move the camera. + */ + @JmeThread + private void finishCameraMoving(@NotNull KeyState key, boolean force) { + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "finish camera moving[" + cameraFlying + "] for key " + key + ", force = " + force); + } + + if (key != KeyState.KEY_ANY) { + keyStates[key.ordinal()] = false; + } + + if (cameraFlying.get() == 0) { + return; + } + + if (force || cameraFlying.decrementAndGet() == 0) { + + cameraFlying.set(0); + + var camera = editor3dPart.getCamera(); + var direction = camera.getDirection() + .multLocal(savedTargetDistance); + var location = camera.getLocation() + .add(direction); + + editorCamera.setTargetDistance(savedTargetDistance); + cameraNode.setLocalTranslation(location); + + Arrays.fill(keyStates, false); + } + } + + /** + * Move a camera to direction. + * + * @param value the value to move. + */ + @JmeThread + private void flyCameraForward(float value, boolean isAction, boolean isPressed, @NotNull KeyState key) { + + if (!canCameraFly()) { + return; + } else if (isAction && isPressed) { + startCameraFlying(key); + } else if (isAction) { + finishCameraMoving(key, false); + } + + if (!canCameraFly() || isAction) { + return; + } + + var direction = editorCamera.getDirection(); + direction.multLocal(value * cameraFlySpeed); + direction.addLocal(cameraNode.getLocalTranslation()); + + cameraNode.setLocalTranslation(direction); + } + + /** + * Move a camera to side. + * + * @param value the value to move. + */ + @JmeThread + private void flyCameraSide(float value, boolean isAction, boolean isPressed, @NotNull KeyState key) { + + if (!canCameraFly()) { + return; + } else if (isAction && isPressed) { + startCameraFlying(key); + } else if (isAction) { + finishCameraMoving(key, false); + } + + if (!canCameraFly() || isAction) { + return; + } + + var left = editorCamera.getLeft(); + left.multLocal(value * cameraFlySpeed); + left.addLocal(cameraNode.getLocalTranslation()); + + cameraNode.setLocalTranslation(left); + } + + + /** + * Move a mouse on X axis. + * + * @param value the value to move. + */ + @JmeThread + protected void moveCameraHorizontal(float value) { + + if (!canCameraMove()) { + return; + } + + var camera = editor3dPart.getCamera(); + var left = camera.getLeft(); + left.multLocal(value * (5F + editorCamera.getTargetDistance())); + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "moveCameraHorizontal() -> left[" + left + "], " + "node " + + "position[" + cameraNode.getLocalTranslation() + "]"); + } + + left.addLocal(cameraNode.getLocalTranslation()); + + cameraNode.setLocalTranslation(left); + } + + /** + * Move a mouse on Y axis. + * + * @param value the value to move. + */ + @JmeThread + protected void moveCameraVertical(float value) { + + if (!canCameraMove()) { + return; + } + + var camera = editor3dPart.getCamera(); + var up = camera.getUp(); + up.multLocal(value * (5F + editorCamera.getTargetDistance())); + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "moveCameraVertical() -> up[" + up + "], " + "node " + + "position[" + cameraNode.getLocalTranslation() + "]"); + } + + up.addLocal(cameraNode.getLocalTranslation()); + + cameraNode.setLocalTranslation(up); + } + + @JmeThread + private boolean canCameraMove() { + + var isButtonMiddleDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_BUTTON_MIDDLE_DOWN); + var isShiftDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_SHIFT_DOWN); + var isCameraFlying = isCameraFlying(); + + if (Config.DEV_CAMERA_CHECKS_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "Can camera move? middleButton[" + isButtonMiddleDown + "], " + + "shift[" + isShiftDown + "], flying[" + isCameraFlying + "]"); + } + + return isButtonMiddleDown && isShiftDown && !isCameraFlying && needMovableCamera; + } + + @JmeThread + private boolean canCameraFly() { + var isButtonMiddleDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_BUTTON_MIDDLE_DOWN); + var isShiftDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_SHIFT_DOWN); + return isButtonMiddleDown && !isShiftDown && needMovableCamera; + } + + /** + * Check camera changes. + * + * @param editorCamera the editor's camera. + */ + @JmeThread + protected void checkCameraChanges(@NotNull EditorCamera editorCamera) { + + int changes = 0; + + var cameraLocation = cameraNode.getLocalTranslation(); + + var hRotation = editorCamera.getHRotation(); + var vRotation = editorCamera.getVRotation(); + var targetDistance = editorCamera.getTargetDistance(); + + if (!prevState.cameraLocation.equals(cameraLocation)) { + changes++; + } else if (prevState.hRotation != hRotation || prevState.vRotation != vRotation) { + changes++; + } else if (prevState.targetDistance != targetDistance) { + changes++; + } else if (prevState.cameraFlySpeed != cameraFlySpeed) { + changes++; + } + + if (changes > 0) { + notifyChangedState(new CameraState(cameraLocation.clone(), hRotation, vRotation, targetDistance, cameraFlySpeed)); + } + + prevState.cameraLocation.set(cameraLocation); + prevState.hRotation = hRotation; + prevState.vRotation = vRotation; + prevState.targetDistance = targetDistance; + prevState.cameraFlySpeed = cameraFlySpeed; + } + + /** + * Notify about changed camera's state. + * + * @param cameraState the camera's state. + */ + @JmeThread + protected void notifyChangedState(@NotNull CameraState cameraState) { + + var fileEditor = editor3dPart.getFileEditor(); + + executorManager.addFxTask(() -> + fileEditor.notify(new CameraChangedFileEditorEvent(this, cameraState))); + } + + /** + * Update the camera's state to this camera. + * + * @param cameraState the camera's state. + */ + @JmeThread + public void applyState(@NotNull CameraState cameraState) { + + prevState.cameraLocation.set(cameraState.getCameraLocation()); + prevState.hRotation = cameraState.getHRotation(); + prevState.vRotation = cameraState.getVRotation(); + prevState.targetDistance = cameraState.getTargetDistance(); + prevState.cameraFlySpeed = cameraState.getCameraFlySpeed(); + + editorCamera.setTargetHRotation(cameraState.getHRotation()); + editorCamera.setTargetVRotation(cameraState.getVRotation()); + editorCamera.setTargetDistance(cameraState.getTargetDistance()); + + cameraNode.setLocalTranslation(cameraState.getCameraLocation()); + + editorCamera.update(1); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/InputStateEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/InputStateEditor3dPartControl.java new file mode 100644 index 00000000..6885a26e --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/InputStateEditor3dPartControl.java @@ -0,0 +1,117 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import static com.ss.rlib.common.util.array.ArrayFactory.toArray; +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.controls.Trigger; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * The control to store input state of the editor 3d part. + * + * @author JavaSaBr + */ +public class InputStateEditor3dPartControl extends BaseInputEditor3dPartControl + implements ActionListener { + + public static final String PROP_IS_CONTROL_DOWN = "inputStateEditor.isControlDown"; + public static final String PROP_IS_ALT_DOWN = "inputStateEditor.isAltDown"; + public static final String PROP_IS_SHIFT_DOWN = "inputStateEditor.isShiftDown"; + public static final String PROP_IS_BUTTON_LEFT_DOWN = "inputStateEditor.isButtonLeftDown"; + public static final String PROP_IS_BUTTON_MIDDLE_DOWN = "inputStateEditor.isButtonMiddleDown"; + public static final String PROP_IS_BUTTON_RIGHT_DOWN = "inputStateEditor.isButtonRightDown"; + + private static final String[] PROPERTIES = { + PROP_IS_CONTROL_DOWN, + PROP_IS_ALT_DOWN, + PROP_IS_SHIFT_DOWN, + PROP_IS_BUTTON_LEFT_DOWN, + PROP_IS_BUTTON_MIDDLE_DOWN, + PROP_IS_BUTTON_RIGHT_DOWN + }; + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final ObjectDictionary MULTI_TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger[].class); + + private static final String MOUSE_RIGHT_CLICK = "jMB.inputStateEditor.mouseRightClick"; + private static final String MOUSE_LEFT_CLICK = "jMB.inputStateEditor.mouseLeftClick"; + private static final String MOUSE_MIDDLE_CLICK = "jMB.inputStateEditor.mouseMiddleClick"; + + private static final String KEY_CTRL = "jMB.inputStateEditor.keyCtrl"; + private static final String KEY_ALT = "jMB.inputStateEditor.keyAlt"; + private static final String KEY_SHIFT = "jMB.inputStateEditor.keyShift"; + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(MOUSE_RIGHT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + TRIGGERS.put(MOUSE_LEFT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + TRIGGERS.put(MOUSE_MIDDLE_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); + + MULTI_TRIGGERS.put(KEY_CTRL, toArray(new KeyTrigger(KeyInput.KEY_RCONTROL), new KeyTrigger(KeyInput.KEY_LCONTROL))); + MULTI_TRIGGERS.put(KEY_SHIFT, toArray(new KeyTrigger(KeyInput.KEY_RSHIFT), new KeyTrigger(KeyInput.KEY_LSHIFT))); + MULTI_TRIGGERS.put(KEY_ALT, toArray(new KeyTrigger(KeyInput.KEY_RMENU), new KeyTrigger(KeyInput.KEY_LMENU))); + + Array mappings = TRIGGERS.keyArray(String.class); + mappings.addAll(MULTI_TRIGGERS.keyArray(String.class)); + + MAPPINGS = mappings.toArray(String.class); + } + + @NotNull + private final ObjectDictionary state; + + public InputStateEditor3dPartControl(@NotNull ExtendableEditor3dPart editor3dPart) { + super(editor3dPart); + this.state = ObjectDictionary.ofType(String.class, Boolean.class); + + actionHandlers.put(MOUSE_LEFT_CLICK, (isPressed, tpf) -> state.put(PROP_IS_BUTTON_LEFT_DOWN, isPressed)); + actionHandlers.put(MOUSE_RIGHT_CLICK, (isPressed, tpf) -> state.put(PROP_IS_BUTTON_RIGHT_DOWN, isPressed)); + actionHandlers.put(MOUSE_MIDDLE_CLICK, (isPressed, tpf) -> state.put(PROP_IS_BUTTON_MIDDLE_DOWN, isPressed)); + actionHandlers.put(KEY_ALT, (isPressed, tpf) -> state.put(PROP_IS_ALT_DOWN, isPressed)); + actionHandlers.put(KEY_CTRL, (isPressed, tpf) -> state.put(PROP_IS_CONTROL_DOWN, isPressed)); + actionHandlers.put(KEY_SHIFT, (isPressed, tpf) -> state.put(PROP_IS_SHIFT_DOWN, isPressed)); + + for (var property : PROPERTIES) { + state.put(property, false); + } + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + MULTI_TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + + inputManager.addListener(this, MAPPINGS); + } + + @Override + @JmeThread + public boolean hasProperty(@NotNull String propertyId) { + return state.containsKey(propertyId); + } + + @Override + @JmeThread + public boolean getBooleanProperty(@NotNull String propertyId) { + return Boolean.TRUE.equals(state.get(propertyId)); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/KeyEventRedirectEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/KeyEventRedirectEditor3dPartControl.java new file mode 100644 index 00000000..b6ddf62a --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/KeyEventRedirectEditor3dPartControl.java @@ -0,0 +1,76 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.editor.event.KeyActionFileEditorEvent; +import com.ss.builder.util.JmeUtils; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.editor.FileEditor; +import com.ss.rlib.common.util.ObjectUtils; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.scene.input.KeyCode; +import org.jetbrains.annotations.NotNull; + +/** + * The control to redirect some input events from {@link Editor3dPart} to {@link FileEditor}. + * + * @author JavaSaBr + */ +public class KeyEventRedirectEditor3dPartControl extends BaseInputEditor3dPartControl + implements ActionListener { + + private static final KeyCode[] KEY_CODES = new KeyCode[Byte.MAX_VALUE * 3]; + + static { + KEY_CODES[KeyInput.KEY_C] = KeyCode.C; + KEY_CODES[KeyInput.KEY_S] = KeyCode.S; + KEY_CODES[KeyInput.KEY_R] = KeyCode.R; + KEY_CODES[KeyInput.KEY_DELETE] = KeyCode.DELETE; + KEY_CODES[KeyInput.KEY_P] = KeyCode.P; + KEY_CODES[KeyInput.KEY_L] = KeyCode.L; + } + + @NotNull + private final ObjectDictionary triggers; + + @NotNull + private final String[] mappings; + + protected KeyEventRedirectEditor3dPartControl( + @NotNull ExtendableEditor3dPart editor3dPart, + @NotNull ObjectDictionary triggers, + @NotNull String[] mappings + ) { + super(editor3dPart); + this.triggers = triggers; + this.mappings = mappings; + + triggers.forEach(actionHandlers, (handlers, mapping, trigger) -> + handlers.put(mapping, (isPressed, tpf) -> + makeHandler(editor3dPart, KEY_CODES[trigger.getKeyCode()], isPressed))); + } + + @BackgroundThread + private void makeHandler(@NotNull ExtendableEditor3dPart editor3dPart, @NotNull KeyCode keyCode, boolean isPressed) { + + var fileEditor = editor3dPart.getFileEditor(); + var isControlDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN); + var isShiftDown = editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_SHIFT_DOWN); + var isButtonMiddleDown =editor3dPart.getBooleanProperty(InputStateEditor3dPartControl.PROP_IS_BUTTON_MIDDLE_DOWN); + + fileEditor.notify(new KeyActionFileEditorEvent(this, ObjectUtils.notNull(keyCode), isPressed, + isControlDown, isShiftDown, isButtonMiddleDown)); + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + triggers.forEach(inputManager, JmeUtils::addMapping); + inputManager.addListener(this, mappings); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/PaintingSupportEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/PaintingSupportEditor3dPartControl.java new file mode 100644 index 00000000..2ccb909b --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/PaintingSupportEditor3dPartControl.java @@ -0,0 +1,301 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import static com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart.PROP_IS_EDITING; +import static com.ss.builder.jme.editor.part3d.control.impl.InputStateEditor3dPartControl.PROP_IS_CONTROL_DOWN; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_IGNORE_RAY_CAST; +import com.jme3.collision.CollisionResult; +import com.jme3.input.InputManager; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.controls.Trigger; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.event.impl.FinishEditingEvent; +import com.ss.builder.jme.editor.part3d.event.impl.StartEditingEvent; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.*; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.painting.PaintingInput; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.event.impl.FinishEditingEvent; +import com.ss.builder.jme.editor.part3d.event.impl.StartEditingEvent; +import com.ss.builder.util.*; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.scene.input.MouseButton; +import org.jetbrains.annotations.NotNull; + +/** + * The control to implement painting support on the scene editor 3d part. + * + * @author JavaSaBr + */ +public class PaintingSupportEditor3dPartControl + extends BaseInputEditor3dPartControl { + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final String MOUSE_RIGHT_CLICK = "jMB.paintingSupportEditor.mouseRightClick"; + private static final String MOUSE_LEFT_CLICK = "jMB.paintingSupportEditor.mouseLeftClick"; + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(MOUSE_RIGHT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + TRIGGERS.put(MOUSE_LEFT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + /** + * The cursor node. + */ + @NotNull + private final Node cursorNode; + + /** + * The markers node. + */ + @NotNull + private final Node markersNode; + + /** + * The flag of painting mode. + */ + private boolean paintingMode; + + public PaintingSupportEditor3dPartControl(@NotNull T editor3dPart) { + super(editor3dPart); + + this.cursorNode = new Node("Cursor node"); + this.markersNode = new Node("Markers node"); + + actionHandlers.put(MOUSE_LEFT_CLICK, (isPressed, tpf) -> { + if (paintingMode) { + if (isPressed) { + startPainting(getPaintingInput(MouseButton.PRIMARY)); + } else { + finishPainting(getPaintingInput(MouseButton.PRIMARY)); + } + } + }); + actionHandlers.put(MOUSE_RIGHT_CLICK, (isPressed, tpf) -> { + if (paintingMode) { + if (isPressed) { + startPainting(getPaintingInput(MouseButton.SECONDARY)); + } else { + finishPainting(getPaintingInput(MouseButton.SECONDARY)); + } + } + }); + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + inputManager.addListener(getActionListener(), MAPPINGS); + } + + /** + * Start painting. + */ + @JmeThread + private void startPainting(@NotNull PaintingInput input) { + + var control = PaintingUtils.getPaintingControl(cursorNode); + var paintedModel = PaintingUtils.getPaintedModel(cursorNode); + + if (control == null || paintedModel == null || control.isStartedPainting()) { + return; + } + + control.startPainting(input, cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); + } + + /** + * Finish painting. + */ + @JmeThread + private void finishPainting(@NotNull PaintingInput input) { + + var control = PaintingUtils.getPaintingControl(cursorNode); + var paintedModel = PaintingUtils.getPaintedModel(control); + + if (control == null || paintedModel == null) { + return; + } else if (!control.isStartedPainting() || control.getCurrentInput() != input) { + return; + } + + control.finishPainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); + } + + @Override + @JmeThread + public void postCameraUpdate(float tpf) { + if (paintingMode) { + updatePaintingNodes(); + updatePainting(tpf); + } + } + + /** + * Update painting. + */ + @JmeThread + private void updatePainting(float tpf) { + + var control = PaintingUtils.getPaintingControl(cursorNode); + var model = PaintingUtils.getPaintedModel(control); + + if (control == null || model == null || !control.isStartedPainting()) { + return; + } + + control.updatePainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation(), tpf); + } + + /** + * Update editing nodes. + */ + @JmeThread + private void updatePaintingNodes() { + + if (!paintingMode) { + return; + } + + var control = PaintingUtils.getPaintingControl(cursorNode); + var paintedModel = PaintingUtils.getPaintedModel(control); + + if (paintedModel == null) { + return; + } + + var collisions = GeomUtils.getCollisionsFromCursor(paintedModel, editor3dPart.getCamera()); + + if (collisions.size() < 1) { + return; + } + + CollisionResult result = null; + + for (var collision : collisions) { + + var geometry = collision.getGeometry(); + var parent = NodeUtils.findParent(geometry, spatial -> + spatial.getUserData(AbstractSceneEditor3dPart.KEY_IGNORE_RAY_CAST) == Boolean.TRUE); + + if (parent == null) { + result = collision; + break; + } + } + + if (result == null) { + result = collisions.getClosestCollision(); + } + + var contactPoint = result.getContactPoint(); + var contactNormal = result.getContactNormal(); + + var local = LocalObjects.get(); + var rotation = local.nextRotation(); + rotation.lookAt(contactNormal, Vector3f.UNIT_Y); + + cursorNode.setLocalRotation(rotation); + cursorNode.setLocalTranslation(contactPoint); + } + + /** + * Get the painting input. + * + * @param mouseButton the mouse button. + * @return the painting input. + */ + @FromAnyThread + protected @NotNull PaintingInput getPaintingInput(@NotNull MouseButton mouseButton) { + + switch (mouseButton) { + case SECONDARY: { + + if (editor3dPart.getBooleanProperty(PROP_IS_CONTROL_DOWN)) { + return PaintingInput.MOUSE_SECONDARY_WITH_CTRL; + } + + return PaintingInput.MOUSE_SECONDARY; + } + case PRIMARY: { + return PaintingInput.MOUSE_PRIMARY; + } + } + + return PaintingInput.MOUSE_PRIMARY; + } + + /** + * Change enabling of painting mode. + * + * @param paintingMode true if painting mode is enabled. + */ + @FromAnyThread + public void changePaintingMode(boolean paintingMode) { + ExecutorManager.getInstance() + .addJmeTask(() -> changePaintingModeInJme(paintingMode)); + } + + /** + * Change enabling of painting mode in jME thread. + * + * @param paintingMode true if painting mode is enabled. + */ + @JmeThread + private void changePaintingModeInJme(boolean paintingMode) { + this.paintingMode = paintingMode; + + var toolNode = editor3dPart.getToolNode(); + + if (paintingMode) { + + if (editor3dPart.getBooleanProperty(EditableSceneEditor3dPart.PROP_IS_EDITING)) { + return; + } + + toolNode.attachChild(cursorNode); + toolNode.attachChild(markersNode); + + editor3dPart.notify(new StartEditingEvent(this)); + + } else { + + toolNode.detachChild(cursorNode); + toolNode.detachChild(markersNode); + + editor3dPart.notify(new FinishEditingEvent(this)); + } + } + + @Override + @JmeThread + public boolean hasProperty(@NotNull String propertyId) { + return EditableSceneEditor3dPart.PROP_IS_EDITING.equals(propertyId); + } + + @Override + @JmeThread + public boolean getBooleanProperty(@NotNull String propertyId) { + return EditableSceneEditor3dPart.PROP_IS_EDITING.equals(propertyId) && paintingMode; + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/SelectionSupportEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/SelectionSupportEditor3dPartControl.java new file mode 100644 index 00000000..7ce74f62 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/SelectionSupportEditor3dPartControl.java @@ -0,0 +1,506 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import static com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart.PROP_IS_EDITING; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_SHAPE_CENTER; +import static com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart.KEY_SHAPE_INIT_SCALE; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.app.Application; +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; +import com.jme3.effect.ParticleEmitter; +import com.jme3.input.InputManager; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.controls.Trigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireBox; +import com.jme3.scene.debug.WireSphere; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.scene.*; +import com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.util.JmeUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The control to implement painting support on the scene editor 3d part. + * + * @author JavaSaBr + */ +public class SelectionSupportEditor3dPartControl + extends BaseInputEditor3dPartControl { + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final ColorRGBA SELECTION_COLOR = new ColorRGBA(1F, 170 / 255F, 64 / 255F, 1F); + + private static final String MOUSE_RIGHT_CLICK = "jMB.selectionSupportEditor.mouseRightClick"; + + private static final String[] MAPPINGS; + + static { + TRIGGERS.put(MOUSE_RIGHT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + /** + * The selection models of selected models. + */ + @NotNull + private final ObjectDictionary selectionShape; + + /** + * The array of selected models. + */ + @NotNull + private final Array selected; + + /** + * Material for selection. + */ + @Nullable + private Material selectionMaterial; + + /** + * The flag of visibility selection. + */ + private boolean showSelection; + + public SelectionSupportEditor3dPartControl(@NotNull T editor3dPart) { + super(editor3dPart); + + this.selected = Array.ofType(Spatial.class); + this.selectionShape = ObjectDictionary.ofType(Spatial.class, Geometry.class); + + actionHandlers.put(MOUSE_RIGHT_CLICK, (isPressed, tpf) -> { + if (!isPressed && !editor3dPart.getBooleanProperty(PROP_IS_EDITING)) { + processSelect(); + } + }); + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + inputManager.addListener(getActionListener(), MAPPINGS); + } + + @Override + @JmeThread + public void initialize(@NotNull Application application) { + + if (selectionMaterial == null) { + selectionMaterial = JmeUtils.coloredWireframeMaterial(SELECTION_COLOR, application.getAssetManager()); + } + } + + /** + * Get the material of selection. + * + * @return the material of selection. + */ + @FromAnyThread + private @NotNull Material getSelectionMaterial() { + return notNull(selectionMaterial); + } + + /** + * Select the objects. + * + * @param objects the objects. + */ + @FromAnyThread + public void select(@NotNull Array objects) { + ExecutorManager.getInstance() + .addJmeTask(() -> selectInJme(objects)); + } + + /** + * Select the object. + * + * @param object the object. + */ + @FromAnyThread + public void select(@NotNull Spatial object) { + ExecutorManager.getInstance() + .addJmeTask(() -> selectInJme(Array.of(object))); + } + + /** + * Select the objects in the jMe thread. + * + * @param objects the objects. + */ + @JmeThread + private void selectInJme(@NotNull Array objects) { + + if (objects.isEmpty()) { + selected.forEach(this, (spatial, ed) -> ed.removeFromSelection(spatial)); + selected.clear(); + } else { + + for (var iterator = selected.iterator(); iterator.hasNext(); ) { + + var spatial = iterator.next(); + if (objects.contains(spatial)) { + continue; + } + + removeFromSelection(spatial); + iterator.fastRemove(); + } + + for (var spatial : objects) { + if (!selected.contains(spatial)) { + addToSelection(spatial); + } + } + } + + //updateToTransform(); + } + + /** + * Add the spatial to selection. + */ + @JmeThread + private void addToSelection(@NotNull Spatial spatial) { + + if (spatial instanceof VisibleOnlyWhenSelected) { + spatial.setCullHint(Spatial.CullHint.Dynamic); + } + + selected.add(spatial); + + if (spatial instanceof NoSelection) { + return; + } + + Geometry shape; + + if (spatial instanceof ParticleEmitter) { + shape = buildBoxSelection(spatial); + } else if (spatial instanceof Geometry) { + shape = buildGeometrySelection((Geometry) spatial); + } else { + shape = buildBoxSelection(spatial); + } + + if (shape == null) { + return; + } + + if (isShowSelection()) { + //toolNode.attachChild(shape); + } + + selectionShape.put(spatial, shape); + } + + /** + * Remove the spatial from the selection. + */ + @JmeThread + private void removeFromSelection(@NotNull Spatial spatial) { + //setTransformCenter(null); + //setToTransform(null); + + var shape = selectionShape.remove(spatial); + + if (shape != null) { + shape.removeFromParent(); + } + + selected.fastRemove(spatial); + + if (spatial instanceof VisibleOnlyWhenSelected) { + spatial.setCullHint(Spatial.CullHint.Always); + } + } + + /** + * Build the selection box for the spatial. + */ + @JmeThread + private Geometry buildBoxSelection(@NotNull Spatial spatial) { + + NodeUtils.updateWorldBound(spatial); + + var bound = spatial.getWorldBound(); + + if (bound instanceof BoundingBox) { + + var boundingBox = (BoundingBox) bound; + var center = boundingBox.getCenter().subtract(spatial.getWorldTranslation()); + var initScale = spatial.getLocalScale().clone(); + + var geometry = WireBox.makeGeometry(boundingBox); + geometry.setName("SelectionShape"); + geometry.setMaterial(getSelectionMaterial()); + geometry.setUserData(KEY_SHAPE_CENTER, center); + geometry.setUserData(KEY_SHAPE_INIT_SCALE, initScale); + + var position = geometry.getLocalTranslation(); + position.addLocal(center); + + geometry.setLocalTranslation(position); + + return geometry; + + } else if (bound instanceof BoundingSphere) { + + var boundingSphere = (BoundingSphere) bound; + + var wire = new WireSphere(); + wire.fromBoundingSphere(boundingSphere); + + var geometry = new Geometry("SelectionShape", wire); + geometry.setMaterial(getSelectionMaterial()); + geometry.setLocalTranslation(spatial.getWorldTranslation()); + + return geometry; + } + + var geometry = WireBox.makeGeometry(new BoundingBox(Vector3f.ZERO, 1, 1, 1)); + geometry.setName("SelectionShape"); + geometry.setMaterial(getSelectionMaterial()); + geometry.setLocalTranslation(spatial.getWorldTranslation()); + + return geometry; + } + + /** + * Build selection grid for the geometry. + */ + @JmeThread + private Geometry buildGeometrySelection(@NotNull Geometry geom) { + + var mesh = geom.getMesh(); + if (mesh == null) { + return null; + } + + var geometry = new Geometry("SelectionShape", mesh); + geometry.setMaterial(getSelectionMaterial()); + geometry.setLocalTransform(geom.getWorldTransform()); + + return geometry; + } + + + @Override + @JmeThread + public void postCameraUpdate(float tpf) { + + selected.forEach(this, (spatial, editor3dPart) -> { + + if (spatial instanceof EditorLightNode) { + spatial = ((EditorLightNode) spatial).getModel(); + } else if (spatial instanceof EditorAudioNode) { + spatial = ((EditorAudioNode) spatial).getModel(); + } else if (spatial instanceof EditorPresentableNode) { + spatial = ((EditorPresentableNode) spatial).getModel(); + } + + if (spatial == null) { + return; + } + + //editor3dPart.updateTransformNode(spatial.getWorldTransform()); + + var selectionShape = editor3dPart.selectionShape; + var shape = selectionShape.get(spatial); + if (shape == null) { + return; + } + + var position = shape.getLocalTranslation(); + position.set(spatial.getWorldTranslation()); + + var center = shape.getUserData(KEY_SHAPE_CENTER); + var initScale = shape.getUserData(KEY_SHAPE_INIT_SCALE); + + if (center != null) { + + if (!initScale.equals(spatial.getLocalScale())) { + + initScale.set(spatial.getLocalScale()); + + NodeUtils.updateWorldBound(spatial); + + var bound = (BoundingBox) spatial.getWorldBound(); + bound.getCenter().subtract(spatial.getWorldTranslation(), center); + + var mesh = (WireBox) shape.getMesh(); + mesh.updatePositions(bound.getXExtent(), bound.getYExtent(), bound.getZExtent()); + } + + position.addLocal(center); + + } else { + shape.setLocalRotation(spatial.getWorldRotation()); + shape.setLocalScale(spatial.getWorldScale()); + } + + shape.setLocalTranslation(position); + }); + } + + /** + * Set true if need to show a selection grid. + * + * @param showSelection true if need to show a selection grid. + */ + @JmeThread + private void setShowSelection(final boolean showSelection) { + this.showSelection = showSelection; + } + + /** + * Return true if a selection grid is showed. + * + * @return true if a selection grid is showed. + */ + @JmeThread + private boolean isShowSelection() { + return showSelection; + } + + /** + * Update showing state of selection grid. + * + * @param showSelection true if need to show selection grid. + */ + @FromAnyThread + public void updateShowSelection(boolean showSelection) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateShowSelectionInJme(showSelection)); + } + + /** + * Update showing state of selection grid in jME thread. + * + * @param showSelection true if need to show selection grid. + */ + @JmeThread + private void updateShowSelectionInJme(boolean showSelection) { + + if (isShowSelection() == showSelection) { + return; + } + + if (showSelection && !selectionShape.isEmpty()) { + // selectionShape.forEach(toolNode::attachChild); + } else if (!showSelection && !selectionShape.isEmpty()) { + //selectionShape.forEach(toolNode::detachChild); + } + + setShowSelection(showSelection); + } + + /** + * Handling a click in the area of the editor. + */ + @JmeThread + private void processSelect() { + + /*var anyGeometry = GeomUtils.getGeometryFromCursor(modelNode, getCamera()); + var currentModel = notNull(getCurrentModel()); + + Object toSelect = anyGeometry == null ? null : findToSelect(anyGeometry); + + if (toSelect == null && anyGeometry != null) { + var modelGeometry = GeomUtils.getGeometryFromCursor(currentModel, getCamera()); + toSelect = modelGeometry == null ? null : findToSelect(modelGeometry); + } + + var result = toSelect; + + ExecutorManager.getInstance() + .addFxTask(() -> notifySelected(result));*/ + } + + + /** + * Find to select object. + * + * @param object the object + * @return the object + */ + @JmeThread + protected @Nullable Object findToSelect(@NotNull Object object) { + + /* for (var finder : SELECTION_FINDERS.getExtensions()) { + var spatial = finder.find(object); + if (spatial != null && spatial.isVisible()) { + return spatial; + } + } + + if (object instanceof Geometry) { + + var spatial = (Spatial) object; + var parent = NodeUtils.findParent(spatial, 2); + + var lightNode = parent == null ? null : getLightNode(parent); + + if (lightNode != null) { + return lightNode; + } + + var audioNode = parent == null ? null : getAudioNode(parent); + + if (audioNode != null) { + return audioNode; + } + + parent = NodeUtils.findParent(spatial, AssetLinkNode.class::isInstance); + + if (parent != null) { + return parent; + } + + parent = NodeUtils.findParent(spatial, + p -> Boolean.TRUE.equals(p.getUserData(KEY_LOADED_MODEL))); + + if (parent != null) { + return parent; + } + } + + if (object instanceof Spatial) { + + var spatial = (Spatial) object; + + if (!spatial.isVisible()) { + return null; + } else if (findParent(spatial, sp -> !sp.isVisible()) != null) { + return null; + } else if (findParent(spatial, sp -> sp == getCurrentModel()) == null) { + return null; + } + } + + return object;*/ + return null; + } + + @FxThread + private void notifySelected(@Nullable Object object) { + //fileEditor.notifySelected(object); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/TransformationSupportEditor3dPartControl.java b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/TransformationSupportEditor3dPartControl.java new file mode 100644 index 00000000..afca90cf --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/control/impl/TransformationSupportEditor3dPartControl.java @@ -0,0 +1,513 @@ +package com.ss.builder.jme.editor.part3d.control.impl; + +import com.jme3.app.Application; +import com.jme3.asset.AssetManager; +import com.jme3.input.InputManager; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.controls.Trigger; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Transform; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.control.transform.*; +import com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.util.JmeUtils; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The control to implement painting support on the scene editor 3d part. + * + * @author JavaSaBr + */ +public class TransformationSupportEditor3dPartControl + extends BaseInputEditor3dPartControl implements EditorTransformSupport { + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, Trigger.class); + + private static final String MOUSE_LEFT_CLICK = "jMB.transformationSupportEditor.mouseLeftClick"; + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(MOUSE_LEFT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + /** + * The node for the placement of transform controls. + */ + @NotNull + private final Node transformToolNode; + + /** + * The difference between the previous point of transformation and new. + */ + @NotNull + private final Vector3f transformDelta; + + /** + * The nodes with transformation control models. + */ + @NotNull + private final Node moveTool, rotateTool, scaleTool; + + /** + * The plane for calculation transforms. + */ + @NotNull + private final Node collisionPlane; + + @NotNull + private final ObjectDictionary transformationTypeToNode; + + /** + * The transformation mode. + */ + @NotNull + private TransformationMode transformMode; + + /** + * The current type of transformation. + */ + @NotNull + private TransformType transformType; + + /** + * The current direction of transformation. + */ + @NotNull + private PickedAxis pickedAxis; + + /** + * Center of transformation. + */ + @Nullable + private Transform transformCenter; + + /** + * The original transformation. + */ + @Nullable + private Transform originalTransform; + + /** + * Object to transform. + */ + @Nullable + private Spatial toTransform; + + /** + * The flag of existing active transformation. + */ + private boolean activeTransform; + + private boolean initialized; + + public TransformationSupportEditor3dPartControl(@NotNull T editor3dPart) { + super(editor3dPart); + + this.transformToolNode = new Node("TransformToolNode"); + this.transformMode = TransformationMode.GLOBAL; + this.transformType = TransformType.MOVE_TOOL; + this.pickedAxis = PickedAxis.NONE; + this.transformDelta = new Vector3f(Float.NaN, Float.NaN, Float.NaN); + this.collisionPlane = new Node(); + this.moveTool = new Node("Move tool"); + this.moveTool.addControl(new MoveToolControl(this)); + this.rotateTool = new Node("Rotate tool"); + this.rotateTool.addControl(new RotationToolControl(this)); + this.scaleTool = new Node("Scale tool"); + this.scaleTool.addControl(new ScaleToolControl(this)); + this.transformationTypeToNode = ObjectDictionary.of( + TransformType.MOVE_TOOL, moveTool, + TransformType.ROTATE_TOOL, rotateTool, + TransformType.SCALE_TOOL, scaleTool + ); + + actionHandlers.put(MOUSE_LEFT_CLICK, (isPressed, tpf) -> { + if (isPressed) { + startTransform(); + } else { + endTransform(); + } + }); + } + + @JmeThread + @Override + public @Nullable Transform getTransformCenter() { + return null; + } + + @JmeThread + @Override + public void setPickedAxis(@NotNull PickedAxis axis) { + + } + + @JmeThread + @Override + public @NotNull PickedAxis getPickedAxis() { + return null; + } + + @JmeThread + @Override + public @NotNull EditorTransformSupport.TransformationMode getTransformationMode() { + return null; + } + + @Override + @JmeThread + public @NotNull Node getCollisionPlane() { + return collisionPlane; + } + + @JmeThread + @Override + public void setTransformDeltaX(float transformDeltaX) { + + } + + @JmeThread + @Override + public void setTransformDeltaY(float transformDeltaY) { + + } + + @JmeThread + @Override + public void setTransformDeltaZ(float transformDeltaZ) { + + } + + @JmeThread + @Override + public float getTransformDeltaX() { + return 0; + } + + @JmeThread + @Override + public float getTransformDeltaY() { + return 0; + } + + @JmeThread + @Override + public float getTransformDeltaZ() { + return 0; + } + + @JmeThread + @Override + public @Nullable Spatial getToTransform() { + return null; + } + + @JmeThread + @Override + public void notifyTransformed(@NotNull Spatial spatial) { + + } + + @Override + @JmeThread + public @NotNull Camera getCamera() { + return editor3dPart.getCamera(); + } + + @Override + @JmeThread + public void register(@NotNull InputManager inputManager) { + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + inputManager.addListener(getActionListener(), MAPPINGS); + } + + /** + * Create manipulators. + * + * @param assetManager the asset manager. + */ + @JmeThread + private void initializeManipulators(@NotNull AssetManager assetManager) { + + if (initialized) { + return; + } + + var transparentMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + + var renderState = transparentMaterial.getAdditionalRenderState(); + renderState.setFaceCullMode(RenderState.FaceCullMode.Off); + renderState.setWireframe(true); + + var size = 20000F; + + var collisionGeometry = new Geometry("plane", new Quad(size, size)); + collisionGeometry.setMaterial(transparentMaterial); + collisionGeometry.setLocalTranslation(-size / 2, -size / 2, 0); + + var redMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + redMaterial.setColor("Color", ColorRGBA.Red); + + var blueMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + blueMaterial.setColor("Color", ColorRGBA.Blue); + + var greenMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + greenMaterial.setColor("Color", ColorRGBA.Green); + + var moveTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_move.j3o"); + moveTool.getChild("move_x").setMaterial(redMaterial); + moveTool.getChild("collision_move_x").setMaterial(redMaterial); + moveTool.getChild("collision_move_x").setCullHint(Spatial.CullHint.Always); + moveTool.getChild("move_y").setMaterial(blueMaterial); + moveTool.getChild("collision_move_y").setMaterial(blueMaterial); + moveTool.getChild("collision_move_y").setCullHint(Spatial.CullHint.Always); + moveTool.getChild("move_z").setMaterial(greenMaterial); + moveTool.getChild("collision_move_z").setMaterial(greenMaterial); + moveTool.getChild("collision_move_z").setCullHint(Spatial.CullHint.Always); + moveTool.scale(0.2f); + + var rotateTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_rotate.j3o"); + rotateTool.getChild("rot_x").setMaterial(redMaterial); + rotateTool.getChild("collision_rot_x").setMaterial(redMaterial); + rotateTool.getChild("collision_rot_x").setCullHint(Spatial.CullHint.Always); + rotateTool.getChild("rot_y").setMaterial(blueMaterial); + rotateTool.getChild("collision_rot_y").setMaterial(blueMaterial); + rotateTool.getChild("collision_rot_y").setCullHint(Spatial.CullHint.Always); + rotateTool.getChild("rot_z").setMaterial(greenMaterial); + rotateTool.getChild("collision_rot_z").setMaterial(greenMaterial); + rotateTool.getChild("collision_rot_z").setCullHint(Spatial.CullHint.Always); + rotateTool.scale(0.2f); + + var scaleTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_scale.j3o"); + scaleTool.getChild("scale_x").setMaterial(redMaterial); + scaleTool.getChild("collision_scale_x").setMaterial(redMaterial); + scaleTool.getChild("collision_scale_x").setCullHint(Spatial.CullHint.Always); + scaleTool.getChild("scale_y").setMaterial(blueMaterial); + scaleTool.getChild("collision_scale_y").setMaterial(blueMaterial); + scaleTool.getChild("collision_scale_y").setCullHint(Spatial.CullHint.Always); + scaleTool.getChild("scale_z").setMaterial(greenMaterial); + scaleTool.getChild("collision_scale_z").setMaterial(greenMaterial); + scaleTool.getChild("collision_scale_z").setCullHint(Spatial.CullHint.Always); + scaleTool.scale(0.2f); + + this.moveTool.attachChild(moveTool); + this.rotateTool.attachChild(rotateTool); + this.scaleTool.attachChild(scaleTool); + this.collisionPlane.attachChild(collisionGeometry); + + initialized = true; + } + + @Override + @JmeThread + public void initialize(@NotNull Application application) { + initializeManipulators(application.getAssetManager()); + } + + @Override + @JmeThread + public void preCameraUpdate(float tpf) { + + // Transform Selected Objects! + /*if (!activeTransform || selectionCenter == null) { + return; + }*/ + + transformToolNode.detachAllChildren(); + transformationTypeToNode.getOptional(transformType) + .map(node -> node.getControl(TransformControl.class)) + .ifPresent(TransformControl::processTransform); + } + + @Override + @JmeThread + public void postCameraUpdate(float tpf) { + + transformToolNode.detachAllChildren(); + transformationTypeToNode.getOptional(transformType) + .ifPresent(transformToolNode::attachChild); + + // FIXME change when will support transform multi-nodes + /* if (selected.size() != 1) { + toolNode.detachChild(transformToolNode); + } else if (!isPaintingMode()) { + toolNode.attachChild(transformToolNode); + }*/ + } + + /** + * Update the transformation node. + */ + @JmeThread + private void updateTransformNode(@Nullable Transform transform) { + + if (transform == null) { + return; + } + + var transformationMode = getTransformationMode(); + var location = transform.getTranslation(); + var positionOnCamera = JmeUtils.getPositionOnCamera(location, editor3dPart.getCamera()); + + transformToolNode.setLocalTranslation(positionOnCamera); + transformToolNode.setLocalScale(1.5F); + transformToolNode.setLocalRotation(transformationMode.getToolRotation(transform, getCamera())); + } + + /** + * Update transformation. + */ + @FromAnyThread + private void updateToTransform() { + //setToTransform(selected.first()); + } + + /** + * Update the transformation's center. + */ + @JmeThread + private void updateTransformCenter() { + + var toTransform = getToTransform(); + var transform = toTransform == null ? null : toTransform.getLocalTransform().clone(); + var originalTransform = transform == null ? null : transform.clone(); + + //setTransformCenter(transform); + //setOriginalTransform(originalTransform); + } + + /** + * Finish the transformation of the model. + */ + @JmeThread + private void endTransform() { + + /*if (!isActiveTransform()) { + return; + } + + var originalTransform = getOriginalTransform(); + var toTransform = getToTransform(); + var currentModel = getCurrentModel(); + + if (currentModel == null) { + LOGGER.warning(this, "not found current model for finishing transform..."); + return; + } else if (originalTransform == null || toTransform == null) { + LOGGER.warning(this, "not found originalTransform or toTransform"); + return; + } + + POST_TRANSFORM_HANDLERS.getExtensions() + .forEach(handler -> handler.handle(toTransform)); + + var oldValue = originalTransform.clone(); + var newValue = toTransform.getLocalTransform().clone(); + + var operation = new PropertyOperation(toTransform, + "internal_transformation", newValue, oldValue); + + operation.setApplyHandler((spatial, transform) -> { + + var preHandlers = PRE_TRANSFORM_HANDLERS.getExtensions(); + var postHandlers = POST_TRANSFORM_HANDLERS.getExtensions(); + + preHandlers.forEach(handler -> handler.handle(spatial)); + try { + spatial.setLocalTransform(transform); + } finally { + postHandlers.forEach(handler -> handler.handle(spatial)); + } + }); + + setPickedAxis(PickedAxis.NONE); + setActiveTransform(false); + setTransformDeltaX(Float.NaN); + updateTransformCenter(); + + fileEditor.execute(operation);*/ + } + + /** + * Start transformation. + */ + @JmeThread + private boolean startTransform() { + + /*updateTransformCenter(); + + var camera = EditorUtils.getGlobalCamera(); + var inputManager = EditorUtils.getInputManager(); + var cursorPosition = inputManager.getCursorPosition(); + + var collisionResults = new CollisionResults(); + + var position = camera.getWorldCoordinates(cursorPosition, 0f); + var direction = camera.getWorldCoordinates(cursorPosition, 1f) + .subtractLocal(position) + .normalizeLocal(); + + var ray = new Ray(); + ray.setOrigin(position); + ray.setDirection(direction); + + transformToolNode.collideWith(ray, collisionResults); + + if (collisionResults.size() < 1) { + return false; + } + + var toTransform = getToTransform(); + + if (toTransform != null) { + PRE_TRANSFORM_HANDLERS.getExtensions(). + forEach(handler -> handler.handle(toTransform)); + } + + var collisionResult = collisionResults.getClosestCollision(); + var transformType = getTransformType(); + + if (transformType == TransformType.MOVE_TOOL) { + var moveTool = getMoveTool(); + var control = moveTool.getControl(TransformControl.class); + control.setCollisionPlane(collisionResult); + } else if (transformType == TransformType.ROTATE_TOOL) { + var rotateTool = getRotateTool(); + var control = rotateTool.getControl(TransformControl.class); + control.setCollisionPlane(collisionResult); + } else if (transformType == TransformType.SCALE_TOOL) { + var scaleTool = getScaleTool(); + var control = scaleTool.getControl(TransformControl.class); + control.setCollisionPlane(collisionResult); + } + + setActiveTransform(true); + return true;*/ + return false; + } + + @Override + protected void notifyImpl(@NotNull Editor3dPartEvent event) { + super.notifyImpl(event); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/event/AbstractEditor3dPartEvent.java b/src/main/java/com/ss/builder/jme/editor/part3d/event/AbstractEditor3dPartEvent.java new file mode 100644 index 00000000..54272469 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/event/AbstractEditor3dPartEvent.java @@ -0,0 +1,25 @@ +package com.ss.builder.jme.editor.part3d.event; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of an editor 3d part event. + * + * @author JavaSaBr + */ +public abstract class AbstractEditor3dPartEvent implements Editor3dPartEvent { + + @NotNull + private final Object source; + + public AbstractEditor3dPartEvent(@NotNull Object source) { + this.source = source; + } + + @Override + @FromAnyThread + public @NotNull Object getSource() { + return source; + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/event/Editor3dPartEvent.java b/src/main/java/com/ss/builder/jme/editor/part3d/event/Editor3dPartEvent.java new file mode 100644 index 00000000..b3f68973 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/event/Editor3dPartEvent.java @@ -0,0 +1,15 @@ +package com.ss.builder.jme.editor.part3d.event; + +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to implement an event in editor 3d parts. + * + * @author Alex Brui + */ +public interface Editor3dPartEvent { + + @FromAnyThread + @NotNull Object getSource(); +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/FinishEditingEvent.java b/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/FinishEditingEvent.java new file mode 100644 index 00000000..4f40cf91 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/FinishEditingEvent.java @@ -0,0 +1,16 @@ +package com.ss.builder.jme.editor.part3d.event.impl; + +import com.ss.builder.jme.editor.part3d.event.AbstractEditor3dPartEvent; +import org.jetbrains.annotations.NotNull; + +/** + * The event about finishing editing in a scene editor. + * + * @author JavaSaBr + */ +public class FinishEditingEvent extends AbstractEditor3dPartEvent { + + public FinishEditingEvent(@NotNull Object source) { + super(source); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/StartEditingEvent.java b/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/StartEditingEvent.java new file mode 100644 index 00000000..2b5ca325 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/event/impl/StartEditingEvent.java @@ -0,0 +1,17 @@ +package com.ss.builder.jme.editor.part3d.event.impl; + +import com.ss.builder.jme.editor.part3d.event.AbstractEditor3dPartEvent; +import com.ss.builder.jme.editor.part3d.event.AbstractEditor3dPartEvent; +import org.jetbrains.annotations.NotNull; + +/** + * The event about starting editing in a scene editor. + * + * @author JavaSaBr + */ +public class StartEditingEvent extends AbstractEditor3dPartEvent { + + public StartEditingEvent(@NotNull Object source) { + super(source); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractEditor3dPart.java new file mode 100644 index 00000000..39222605 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractEditor3dPart.java @@ -0,0 +1,53 @@ +package com.ss.builder.jme.editor.part3d.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.app.Application; +import com.jme3.app.state.AbstractAppState; +import com.jme3.app.state.AppStateManager; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.editor.FileEditor; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of the {@link Editor3dPart} to use inside {@link FileEditor}. + * + * @author JavaSaBr + */ +public abstract class AbstractEditor3dPart extends AbstractAppState implements Editor3dPart { + + protected static final Logger LOGGER = LoggerManager.getLogger(Editor3dPart.class); + + /** + * The current application. + */ + @Nullable + protected Application application; + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + this.application = application; + } + + @Override + @JmeThread + public void cleanup() { + this.application = null; + super.cleanup(); + } + + /** + * Get the current application. + * + * @return get the current application. + */ + @JmeThread + public @NotNull Application requireApplication() { + return notNull(application); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractExtendableEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractExtendableEditor3dPart.java new file mode 100644 index 00000000..5e8d4ebe --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/AbstractExtendableEditor3dPart.java @@ -0,0 +1,122 @@ +package com.ss.builder.jme.editor.part3d.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.renderer.Camera; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.Editor3dPartControl; +import com.ss.builder.jme.editor.part3d.event.Editor3dPartEvent; +import com.ss.builder.editor.FileEditor; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of the {@link Editor3dPart} to use inside {@link FileEditor}. + * + * @param the type of file editor + * @author JavaSaBr + */ +public abstract class AbstractExtendableEditor3dPart extends AbstractEditor3dPart + implements ExtendableEditor3dPart { + + /** + * The owner editor. + */ + @NotNull + protected final T fileEditor; + + /** + * The root node. + */ + @NotNull + protected final Node stateNode; + + /** + * The list of additional controls of this 3d part. + */ + @NotNull + protected final Array controls; + + public AbstractExtendableEditor3dPart(@NotNull T fileEditor) { + this.fileEditor = fileEditor; + this.stateNode = new Node(getClass().getSimpleName()); + this.controls = Array.ofType(Editor3dPartControl.class); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + controls.forEach(application, Editor3dPartControl::initialize); + } + + @Override + @JmeThread + public void cleanup() { + controls.forEach(requireApplication(), Editor3dPartControl::cleanup); + super.cleanup(); + } + + /** + * Get the current application. + * + * @return get the current application. + */ + @JmeThread + public @NotNull Application requireApplication() { + return notNull(application); + } + + /** + * Add the new control. + * + * @param control the new control. + */ + @JmeThread + protected void addControl(@NotNull Editor3dPartControl control) { + this.controls.add(control); + } + + @Override + @JmeThread + public @Nullable C getControl(@NotNull Class type) { + return type.cast(controls.findAnyR(type, Class::isInstance)); + } + + @Override + @JmeThread + public boolean getBooleanProperty(@NotNull String propertyId) { + var control = controls.findAny(propertyId, Editor3dPartControl::hasProperty); + return control != null && control.getBooleanProperty(propertyId); + } + + @Override + @FromAnyThread + public @NotNull T getFileEditor() { + return fileEditor; + } + + @Override + @JmeThread + public @NotNull Node getRootNode() { + return stateNode; + } + + @Override + @JmeThread + public void notify(@NotNull Editor3dPartEvent event) { + controls.forEach(event, Editor3dPartControl::notify); + } + + @Override + @FromAnyThread + public @NotNull Camera getCamera() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/Base3dSceneEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/Base3dSceneEditor3dPart.java new file mode 100644 index 00000000..ad7f6be9 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/Base3dSceneEditor3dPart.java @@ -0,0 +1,106 @@ +package com.ss.builder.jme.editor.part3d.impl; + +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.Editor3dPartControl; +import com.ss.builder.jme.editor.part3d.control.impl.CameraEditor3dPartControl; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.jme.editor.part3d.SavableEditor3dPart; +import com.ss.builder.jme.editor.part3d.UndoableEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.impl.BaseHotKeysEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.control.impl.InputStateEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.UndoableFileEditor; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +/** + * The base implementation of the {@link Editor3dPart} for a file editor. + * + * @param the type of a file editor. + * @author JavaSaBr + */ +public abstract class Base3dSceneEditor3dPart extends AbstractExtendableEditor3dPart implements + UndoableEditor3dPart, SavableEditor3dPart { + + public Base3dSceneEditor3dPart(@NotNull T fileEditor) { + super(fileEditor); + controls.add(new InputStateEditor3dPartControl(this)); + controls.add(new BaseHotKeysEditor3dPartControl<>(this)); + createCameraControl().ifPresent(controls::add); + } + + @BackgroundThread + protected @NotNull Optional createCameraControl() { + return Optional.of(new CameraEditor3dPartControl(this)); + } + + @Override + @JmeThread + public void undo() { + if (fileEditor instanceof UndoableFileEditor) { + ((UndoableFileEditor) fileEditor).undo().join(); + } + } + + @Override + @JmeThread + public void redo() { + if (fileEditor instanceof UndoableFileEditor) { + ((UndoableFileEditor) fileEditor).redo().join(); + } + } + + @Override + @JmeThread + public @NotNull CompletableFuture save() { + return fileEditor.save(); + } + + @Override + @JmeThread + public boolean isDirty() { + return fileEditor.isDirty(); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + + var rootNode = EditorUtils.getRootNode(application); + rootNode.attachChild(stateNode); + + var filterRegistry = RenderFilterRegistry.getInstance(); + filterRegistry.enableFilters(); + } + + @Override + @JmeThread + public void cleanup() { + + var filterRegistry = RenderFilterRegistry.getInstance(); + filterRegistry.disableFilters(); + + var rootNode = EditorUtils.getGlobalRootNode(); + rootNode.detachChild(stateNode); + + super.cleanup(); + } + + @Override + @JmeThread + public void update(float tpf) { + super.update(tpf); + controls.forEach(tpf, Editor3dPartControl::update); + controls.forEach(tpf, Editor3dPartControl::preCameraUpdate); + controls.forEach(tpf, Editor3dPartControl::cameraUpdate); + controls.forEach(tpf, Editor3dPartControl::postCameraUpdate); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/Stats3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/Stats3dPart.java new file mode 100644 index 00000000..bcb42147 --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/Stats3dPart.java @@ -0,0 +1,382 @@ +package com.ss.builder.jme.editor.part3d.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.renderer.Statistics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.ArrayUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The 3D state to get and to show statistics of rendering. + * + * @author JavaSaBr + */ +public class Stats3dPart extends AbstractEditor3dPart { + + private static final AtomicInteger STATISTICS_ENABLED = new AtomicInteger(0); + + /** + * The parent node. + */ + @NotNull + private final Pane parent; + + /** + * The stats parent. + */ + @NotNull + private final GridPane statsContainer; + + /** + * The frame buffer M field. + */ + @NotNull + private final Label frameBuffersMField; + + /** + * The frame buffer F field. + */ + @NotNull + private final Label frameBuffersFField; + + /** + * The frame buffer S field. + */ + @NotNull + private final Label frameBuffersSField; + + /** + * The textures M field. + */ + @NotNull + private final Label texturesMField; + + /** + * The textures F field. + */ + @NotNull + private final Label texturesFField; + + /** + * The textures S field. + */ + @NotNull + private final Label texturesSField; + + /** + * The shaders M field. + */ + @NotNull + private final Label shadersMField; + + /** + * The shaders F field. + */ + @NotNull + private final Label shadersFField; + + /** + * The shaders S field. + */ + @NotNull + private final Label shadersSField; + + /** + * The objects field. + */ + @NotNull + private final Label objectsField; + + /** + * The uniforms field. + */ + @NotNull + private final Label uniformsField; + + /** + * The triangles field. + */ + @NotNull + private final Label trianglesField; + + /** + * The vertices S field. + */ + @NotNull + private final Label verticesField; + + /** + * The filed to show FPS. + */ + @NotNull + private final Label fpsField; + + /** + * The statistics. + */ + @Nullable + private Statistics statistics; + + /** + * The container of stats data. + */ + @Nullable + private int[] statsData; + + /** + * The container of prev stats data. + */ + @Nullable + private int[] prevStatsData; + + private float secondCounter; + private int frameCounter; + + private int fps; + private int prevFps; + + public Stats3dPart(@NotNull Pane parent) { + this.parent = parent; + this.statsContainer = new GridPane(); + this.frameCounter = 0; + this.secondCounter = 0.0f; + this.prevFps = -1; + this.frameBuffersMField = new Label(); + this.frameBuffersFField = new Label(); + this.frameBuffersSField = new Label(); + this.texturesMField = new Label(); + this.texturesFField = new Label(); + this.texturesSField = new Label(); + this.shadersMField = new Label(); + this.shadersFField = new Label(); + this.shadersSField = new Label(); + this.objectsField = new Label(); + this.uniformsField = new Label(); + this.trianglesField = new Label(); + this.verticesField = new Label(); + this.fpsField = new Label(); + createComponents(); + setEnabled(false); + } + + /** + * Create stats fields. + */ + @FxThread + private void createComponents() { + + var frameBuffersMLabel = new Label("FrameBuffers (M)"); + var frameBuffersFLabel = new Label("FrameBuffers (F)"); + var frameBuffersSLabel = new Label("FrameBuffers (S)"); + + var texturesMLabel = new Label("Textures (M)"); + var texturesFLabel = new Label("Textures (F)"); + var texturesSLabel = new Label("Textures (S)"); + + var shadersMLabel = new Label("Shaders (M)"); + var shadersFLabel = new Label("Shaders (F)"); + var shadersSLabel = new Label("Shaders (S)"); + + var objectsLabel = new Label("Objects"); + var uniformsLabel = new Label("Uniforms"); + var trianglesLabel = new Label("Triangles"); + var verticesLabel = new Label("Vertices"); + + var fpsLabel = new Label("Fps"); + + statsContainer.add(frameBuffersMLabel, 0, 0); + statsContainer.add(frameBuffersMField, 1, 0); + statsContainer.add(frameBuffersFLabel, 0, 1); + statsContainer.add(frameBuffersFField, 1, 1); + statsContainer.add(frameBuffersSLabel, 0, 2); + statsContainer.add(frameBuffersSField, 1, 2); + statsContainer.add(texturesMLabel, 0, 3); + statsContainer.add(texturesMField, 1, 3); + statsContainer.add(texturesFLabel, 0, 4); + statsContainer.add(texturesFField, 1, 4); + statsContainer.add(texturesSLabel, 0, 5); + statsContainer.add(texturesSField, 1, 5); + statsContainer.add(shadersMLabel, 0, 6); + statsContainer.add(shadersMField, 1, 6); + statsContainer.add(shadersFLabel, 0, 7); + statsContainer.add(shadersFField, 1, 7); + statsContainer.add(shadersSLabel, 0, 8); + statsContainer.add(shadersSField, 1, 8); + statsContainer.add(objectsLabel, 0, 9); + statsContainer.add(objectsField, 1, 9); + statsContainer.add(uniformsLabel, 0, 10); + statsContainer.add(uniformsField, 1, 10); + statsContainer.add(trianglesLabel, 0, 11); + statsContainer.add(trianglesField, 1, 11); + statsContainer.add(verticesLabel, 0, 12); + statsContainer.add(verticesField, 1, 12); + statsContainer.add(fpsLabel, 0, 13); + statsContainer.add(fpsField, 1, 13); + + FxUtils.addClass(statsContainer, CssClasses.STATS_3D_STATE); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + + this.statistics = application.getRenderer() + .getStatistics(); + + this.statsData = new int[statistics.getLabels().length]; + this.prevStatsData = new int[statistics.getLabels().length]; + + statistics.setEnabled(STATISTICS_ENABLED.incrementAndGet() > 0); + + ExecutorManager.getInstance() + .addFxTask(() -> FxUtils.addChild(parent, statsContainer)); + } + + @Override + @JmeThread + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + + ExecutorManager.getInstance() + .addFxTask(() -> statsContainer.setVisible(enabled)); + } + + /** + * Get the statistics. + * + * @return the statistics. + */ + @FromAnyThread + private @NotNull Statistics getStatistics() { + return notNull(statistics); + } + + /** + * Get the container of stats data. + * + * @return the container of stats data. + */ + @FromAnyThread + private @NotNull int[] getStatsData() { + return notNull(statsData); + } + + /** + * Get the container of prev stats data. + * + * @return the container of prev stats data. + */ + @FromAnyThread + private @Nullable int[] getPrevStatsData() { + return prevStatsData; + } + + @Override + @JmeThread + public void update(float tpf) { + + if (!isEnabled()) { + return; + } + + var application = requireApplication(); + var timer = application.getTimer(); + + secondCounter += timer.getTimePerFrame(); + frameCounter++; + + if (secondCounter >= 1.0f) { + fps = (int) (frameCounter / secondCounter); + if (fps != prevFps) { + secondCounter = 0.0f; + frameCounter = 0; + updateFps(fps); + prevFps = fps; + } + } + + var statsData = getStatsData(); + + var statistics = getStatistics(); + statistics.getData(statsData); + + var prevStatsData = getPrevStatsData(); + + if (Arrays.equals(statsData, prevStatsData)) { + return; + } + + ArrayUtils.copyTo(statsData, prevStatsData); + + var vertices = statsData[0]; + var triangles = statsData[1]; + var uniforms = statsData[2]; + var objects = statsData[3]; + var shadersS = statsData[4]; + var shadersF = statsData[5]; + var shadersM = statsData[6]; + var texturesS = statsData[7]; + var texturesF = statsData[8]; + var texturesM = statsData[9]; + var frameBuffersS = statsData[10]; + var frameBuffersF = statsData[11]; + var frameBuffersM = statsData[12]; + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + verticesField.setText(Integer.toString(vertices)); + trianglesField.setText(Integer.toString(triangles)); + uniformsField.setText(Integer.toString(uniforms)); + objectsField.setText(Integer.toString(objects)); + shadersSField.setText(Integer.toString(shadersS)); + shadersFField.setText(Integer.toString(shadersF)); + shadersMField.setText(Integer.toString(shadersM)); + texturesSField.setText(Integer.toString(texturesS)); + texturesFField.setText(Integer.toString(texturesF)); + texturesMField.setText(Integer.toString(texturesM)); + frameBuffersSField.setText(Integer.toString(frameBuffersS)); + frameBuffersFField.setText(Integer.toString(frameBuffersF)); + frameBuffersMField.setText(Integer.toString(frameBuffersM)); + }); + } + + /** + * Update the FPS value. + */ + @JmeThread + private void updateFps(int fps) { + ExecutorManager.getInstance() + .addFxTask(() -> fpsField.setText(Integer.toString(fps))); + } + + @Override + @JmeThread + public void cleanup() { + super.cleanup(); + + getStatistics().setEnabled(STATISTICS_ENABLED.decrementAndGet() == 0); + + ExecutorManager.getInstance() + .addFxTask(() -> FxUtils.removeChild(parent, statsContainer)); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/audio/AudioViewer3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/audio/AudioViewer3dPart.java new file mode 100644 index 00000000..bd5c00bc --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/audio/AudioViewer3dPart.java @@ -0,0 +1,228 @@ +package com.ss.builder.jme.editor.part3d.impl.audio; + +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioKey; +import com.jme3.audio.AudioNode; +import com.jme3.audio.AudioSource.Status; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.editor.impl.audio.AudioViewerEditor; +import com.ss.builder.jme.editor.part3d.impl.AbstractExtendableEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.rlib.common.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The implementation of an editor app state for the {@link AudioViewerEditor}. + * + * @author JavaSaBr + */ +public class AudioViewer3dPart extends AbstractExtendableEditor3dPart { + + /** + * The previous status. + */ + @Nullable + private volatile Status prevStatus; + + /** + * The audio node. + */ + @Nullable + private AudioNode audioNode; + + /** + * The audio data. + */ + @Nullable + private AudioData audioData; + + /** + * The audio key. + */ + @Nullable + private AudioKey audioKey; + + public AudioViewer3dPart(@NotNull AudioViewerEditor fileEditor) { + super(fileEditor); + } + + @JmeThread + private @NotNull Optional getAudioNodeOpt() { + return Optional.ofNullable(audioNode); + } + + /** + * Load the audio data. + * + * @param audioData the audio data. + * @param audioKey the audio key. + */ + @FromAnyThread + public void load(@NotNull AudioData audioData, @NotNull AudioKey audioKey) { + ExecutorManager.getInstance() + .addJmeTask(() -> loadInJme(audioData, audioKey)); + } + + /** + * Load the audio data in jME thread. + * + * @param audioData the audio data. + * @param audioKey the audio key. + */ + @JmeThread + private @NotNull AudioNode loadInJme(@NotNull AudioData audioData, @NotNull AudioKey audioKey) { + removeAudioNode(); + + this.audioData = audioData; + this.audioKey = audioKey; + + audioNode = new AudioNode(audioData, audioKey); + audioNode.setPositional(false); + + stateNode.attachChild(audioNode); + + return audioNode; + } + + /** + * Remove the current audio node. + */ + @JmeThread + private void removeAudioNode() { + + if (audioNode == null) { + return; + } + + var status = audioNode.getStatus(); + + if (status == Status.Playing || status == Status.Paused) { + audioNode.stop(); + } + + stateNode.detachChild(audioNode); + + this.audioNode = null; + this.prevStatus = null; + } + + /** + * Play the current audio. + */ + @FromAnyThread + public void play() { + ExecutorManager.getInstance() + .addJmeTask(this::playInJme); + } + + /** + * Play the current audio. + */ + @JmeThread + private void playInJme() { + + if (audioNode != null) { + + var status = audioNode.getStatus(); + + if (status == Status.Paused) { + audioNode.play(); + return; + } else if (status == Status.Playing) { + return; + } + } + + var audioData = ObjectUtils.notNull(this.audioData, "audio data can't be null."); + var audioKey = ObjectUtils.notNull(this.audioKey, "audio key can't be null."); + + var audioNode = loadInJme(audioData, audioKey); + audioNode.play(); + } + + @Override + @JmeThread + public void cleanup() { + stopInJme(); + super.cleanup(); + } + + /** + * Pause the current audio. + */ + @FromAnyThread + public void pause() { + ExecutorManager.getInstance() + .addJmeTask(this::pauseInJme); + } + + /** + * Pause the current audio in jME. + */ + @JmeThread + private void pauseInJme() { + getAudioNodeOpt().ifPresent(AudioNode::pause); + } + + /** + * Stop the current audio. + */ + @FromAnyThread + public void stop() { + ExecutorManager.getInstance() + .addJmeTask(this::stopInJme); + } + + /** + * Stop the current audio in jME thread. + */ + @JmeThread + private void stopInJme() { + removeAudioNode(); + notifyChangeStatus(Status.Stopped); + } + + @Override + @JmeThread + public void update(float tpf) { + super.update(tpf); + + var status = getAudioNodeOpt() + .map(AudioNode::getStatus) + .orElse(null); + + if (status != null && status != prevStatus) { + notifyChangeStatus(status); + prevStatus = status; + } + } + + /** + * Get a previous status of playing audio. + * + * @return the previous status of playing audio. + */ + public @Nullable Status getPrevStatus() { + return prevStatus; + } + + @FromAnyThread + private void notifyChangeStatus(@NotNull Status status) { + ExecutorManager.getInstance() + .addFxTask(() -> fileEditor.notifyChangedStatus(status)); + } + + @Override + public String toString() { + return "AudioViewer3dPart{" + + "prevStatus=" + prevStatus + + ", audioNode=" + audioNode + + ", audioData=" + audioData + + ", audioKey=" + audioKey + + "} " + super.toString(); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/material/MaterialEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/material/MaterialEditor3dPart.java new file mode 100644 index 00000000..f27c52ac --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/material/MaterialEditor3dPart.java @@ -0,0 +1,17 @@ +package com.ss.builder.jme.editor.part3d.impl.material; + +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart; +import com.ss.builder.editor.impl.material.MaterialFileEditor; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation the 3D part of the {@link MaterialFileEditor} but it can be reused in other cases. + * + * @author JavaSaBr + */ +public class MaterialEditor3dPart extends BaseMaterialEditor3dPart { + + public MaterialEditor3dPart(@NotNull MaterialFileEditor fileEditor) { + super(fileEditor); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditor3dPart.java new file mode 100644 index 00000000..951fa33a --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditor3dPart.java @@ -0,0 +1,224 @@ +package com.ss.builder.jme.editor.part3d.impl.model; + +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.light.LightProbe; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.impl.CameraEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.editor.impl.model.ModelFileEditor; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link AbstractSceneEditor3dPart} for the {@link ModelFileEditor}. + * + * @author JavaSaBr + */ +public class ModelEditor3dPart extends AbstractSceneEditor3dPart { + + @NotNull + private final JobProgressAdapter probeHandler = new JobProgressAdapter() { + + @Override + public void done(final LightProbe result) { + if (!isInitialized()) return; + notifyProbeComplete(); + } + }; + + /** + * The array of custom skies. + */ + @NotNull + private final Array customSky; + + /** + * The node for the placement of custom sky. + */ + @NotNull + private final Node customSkyNode; + + /** + * The current fast sky. + */ + @Nullable + private Spatial currentFastSky; + + /** + * The frame rate. + */ + private int frame; + + public ModelEditor3dPart(@NotNull ModelFileEditor fileEditor) { + super(fileEditor); + this.customSkyNode = new Node("Custom Sky"); + this.customSky = Array.ofType(Spatial.class); + stateNode.attachChild(customSkyNode); + } + + + /** + * Activate the node with models. + */ + @JmeThread + private void notifyProbeComplete() { + + stateNode.attachChild(modelNode); + stateNode.attachChild(toolNode); + + customSkyNode.detachAllChildren(); + + RenderFilterRegistry.getInstance() + .refreshFilters(); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + frame = 0; + } + + @Override + @JmeThread + public void cleanup() { + super.cleanup(); + stateNode.detachChild(modelNode); + stateNode.detachChild(toolNode); + } + + @Override + @JmeThread + public void update(float tpf) { + super.update(tpf); + + if (frame == 2) { + customSky.forEach(spatial -> customSkyNode.attachChild(spatial.clone(false))); + EditorUtils.updateGlobalLightProbe(probeHandler); + } + + frame++; + } + + /** + * Update light. + * + * @param enabled the enabled. + */ + @FromAnyThread + public void updateLightEnabled(boolean enabled) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateLightEnabledInJme(enabled)); + } + + /** + * The process of updating the light. + */ + @JmeThread + private void updateLightEnabledInJme(boolean enabled) { + + var cameraControl = requireControl(CameraEditor3dPartControl.class); + + if (enabled) { + cameraControl.enableLight(); + } else { + cameraControl.disableLight(); + } + } + + /** + * Change the fast sky. + * + * @param fastSky the fast sky + */ + @FromAnyThread + public void changeFastSky(@Nullable Spatial fastSky) { + ExecutorManager.getInstance() + .addJmeTask(() -> changeFastSkyInJme(fastSky)); + } + + /** + * The process of changing the fast sky. + */ + @JmeThread + private void changeFastSkyInJme(@Nullable Spatial fastSky) { + + if (currentFastSky != null) { + stateNode.detachChild(currentFastSky); + } + + if (fastSky != null) { + stateNode.attachChild(fastSky); + } + + stateNode.detachChild(modelNode); + stateNode.detachChild(toolNode); + + currentFastSky = fastSky; + + frame = 0; + } + + /** + * Add the custom sky. + * + * @param sky the sky. + */ + @FromAnyThread + public void addCustomSky(@NotNull Spatial sky) { + ExecutorManager.getInstance() + .addJmeTask(() -> addCustomSkyInJme(sky)); + } + + /** + * The process of adding the custom sky. + */ + @JmeThread + private void addCustomSkyInJme(@NotNull Spatial sky) { + customSky.add(sky); + } + + /** + * Remove the custom sky. + * + * @param sky the sky + */ + @FromAnyThread + public void removeCustomSky(@NotNull Spatial sky) { + ExecutorManager.getInstance() + .addJmeTask(() -> removeCustomSkyInJme(sky)); + } + + /** + * The process of removing the custom sky. + */ + @JmeThread + private void removeCustomSkyInJme(@NotNull Spatial sky) { + customSky.slowRemove(sky); + } + + /** + * Update the light probe. + */ + @FromAnyThread + public void updateLightProbe() { + ExecutorManager.getInstance() + .addJmeTask(this::updateLightProbeInJme); + } + + @JmeThread + private void updateLightProbeInJme() { + stateNode.detachChild(modelNode); + stateNode.detachChild(toolNode); + frame = 0; + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditorBulletPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditorBulletPart.java new file mode 100644 index 00000000..116711ae --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/model/ModelEditorBulletPart.java @@ -0,0 +1,73 @@ +package com.ss.builder.jme.editor.part3d.impl.model; + +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.app.state.impl.bullet.EditableBulletSceneAppState; +import com.ss.builder.jme.editor.part3d.Editor3dPart; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of editor 3D state to work with Bullet physics. + * + * @author JavaSaBr + */ +public class ModelEditorBulletPart extends EditableBulletSceneAppState implements Editor3dPart { + + @NotNull + private final ModelEditor3dPart editor3dPart; + + public ModelEditorBulletPart(@NotNull ModelEditor3dPart editor3dPart) { + this.editor3dPart = editor3dPart; + } + + @Override + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application app) { + super.initialize(stateManager, app); + + var currentModel = editor3dPart.getCurrentModel(); + + if (currentModel != null) { + updateNode(currentModel, physicsSpace); + } + } + + @Override + protected void rebuildState() { + super.rebuildState(); + + if (!isInitialized()) { + return; + } + + var currentModel = editor3dPart.getCurrentModel(); + + if (currentModel != null) { + updateNode(currentModel, physicsSpace); + } + } + + /** + * Update a spatial. + * + * @param spatial the spatial. + * @param physicsSpace the new physical space or null. + */ + @JmeThread + private void updateNode(@NotNull Spatial spatial, @Nullable PhysicsSpace physicsSpace) { + spatial.depthFirstTraversal(sub -> { + var numControls = sub.getNumControls(); + for (int i = 0; i < numControls; i++) { + var control = sub.getControl(i); + if (control instanceof PhysicsControl) { + ((PhysicsControl) control).setPhysicsSpace(physicsSpace); + } + } + }); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/AbstractSceneEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/AbstractSceneEditor3dPart.java new file mode 100644 index 00000000..40a992df --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/AbstractSceneEditor3dPart.java @@ -0,0 +1,1064 @@ +package com.ss.builder.jme.editor.part3d.impl.scene; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.app.state.AppState; +import com.jme3.asset.AssetNotFoundException; +import com.jme3.audio.AudioNode; +import com.jme3.bounding.BoundingBox; +import com.jme3.light.Light; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RendererException; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.scene.debug.Grid; +import com.jme3.scene.shape.Line; +import com.jme3.scene.shape.Quad; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.EditableSceneEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.impl.CameraEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.control.impl.SelectionSupportEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.control.impl.TransformationSupportEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.impl.scene.handler.ApplyScaleToPhysicsControlsHandler; +import com.ss.builder.jme.editor.part3d.impl.scene.handler.DisableControlsTransformationHandler; +import com.ss.builder.jme.editor.part3d.impl.scene.handler.PhysicsControlTransformationHandler; +import com.ss.builder.jme.editor.part3d.impl.scene.handler.ReactivatePhysicsControlsTransformationHandler; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.plugin.api.editor.part3d.Advanced3dFileEditor3dEditorPart; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.JmeUtils; +import com.ss.editor.extension.property.EditableProperty; +import com.ss.editor.extension.scene.ScenePresentable; +import com.ss.builder.model.scene.EditorAudioNode; +import com.ss.builder.model.scene.EditorLightNode; +import com.ss.builder.model.scene.EditorPresentableNode; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.jme.editor.part3d.control.impl.AbstractSceneEditorHotKeys3dPartControl; +import com.ss.builder.jme.editor.part3d.control.impl.PaintingSupportEditor3dPartControl; +import com.ss.builder.editor.impl.scene.AbstractSceneFileEditor; +import com.ss.builder.util.GeomUtils; +import com.ss.builder.util.NodeUtils; +import com.ss.rlib.common.geom.util.AngleUtils; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The base implementation of the {@link AppState} for the editor. + * + * @param the type of file scene editor. + * @param the type of edited spatial. + * @author JavaSaBr + */ +public abstract class AbstractSceneEditor3dPart + extends Advanced3dFileEditor3dEditorPart implements EditableSceneEditor3dPart { + + /** + * @see SelectionFinder + */ + public static final String EP_SELECTION_FINDER = "AbstractSceneEditor3dPart#selectionFinder"; + + /** + * @see TransformationHandler + */ + public static final String EP_PRE_TRANSFORM_HANDLER = "AbstractSceneEditor3dPart#preTransfromHandler"; + + /** + * @see TransformationHandler + */ + public static final String EP_POST_TRANSFORM_HANDLER = "AbstractSceneEditor3dPart#postTransformHandler"; + + public static final String KEY_LOADED_MODEL = "jMB.sceneEditor.loadedModel"; + public static final String KEY_IGNORE_RAY_CAST = "jMB.sceneEditor.ignoreRayCast"; + public static final String KEY_MODEL_NODE = "jMB.sceneEditor.modelNode"; + public static final String KEY_SHAPE_CENTER = "jMB.sceneEditor.shapeCenter"; + public static final String KEY_SHAPE_INIT_SCALE = "jMB.sceneEditor.initScale"; + + private static final float H_ROTATION = AngleUtils.degreeToRadians(45); + private static final float V_ROTATION = AngleUtils.degreeToRadians(15); + + /** + * The table with models to present lights on a scene. + */ + private static final ObjectDictionary LIGHT_MODEL_TABLE; + + private static final Node AUDIO_NODE_MODEL; + + static { + + var assetManager = EditorUtils.getAssetManager(); + + AUDIO_NODE_MODEL = (Node) assetManager.loadModel("graphics/models/speaker/speaker.j3o"); + + LIGHT_MODEL_TABLE = DictionaryFactory.newObjectDictionary(); + LIGHT_MODEL_TABLE.put(Light.Type.Point, (Node) assetManager.loadModel("graphics/models/light/point_light.j3o")); + LIGHT_MODEL_TABLE.put(Light.Type.Directional, (Node) assetManager.loadModel("graphics/models/light/direction_light.j3o")); + LIGHT_MODEL_TABLE.put(Light.Type.Spot, (Node) assetManager.loadModel("graphics/models/light/spot_light.j3o")); + } + + @FunctionalInterface + public interface SelectionFinder { + + @JmeThread + @Nullable Spatial find(@NotNull Object object); + } + + @FunctionalInterface + public interface TransformationHandler { + + @JmeThread + void handle(@NotNull Spatial object); + } + + private static final ExtensionPoint SELECTION_FINDERS = + ExtensionPointManager.register(EP_SELECTION_FINDER); + + private static final ExtensionPoint PRE_TRANSFORM_HANDLERS = + ExtensionPointManager.register(EP_PRE_TRANSFORM_HANDLER); + + private static final ExtensionPoint POST_TRANSFORM_HANDLERS = + ExtensionPointManager.register(EP_POST_TRANSFORM_HANDLER); + + static { + + // default handlers + var disableControlsHandler = new DisableControlsTransformationHandler(); + var applyScaleToPhysicsControlsHandler = new ApplyScaleToPhysicsControlsHandler(); + + PRE_TRANSFORM_HANDLERS.register(disableControlsHandler::onPreTransform) + .register(applyScaleToPhysicsControlsHandler::onPreTransform); + + POST_TRANSFORM_HANDLERS.register(disableControlsHandler::onPostTransform) + .register(new ReactivatePhysicsControlsTransformationHandler()) + .register(new PhysicsControlTransformationHandler()) + .register(applyScaleToPhysicsControlsHandler::onPostTransform); + } + + /** + * The map with cached light nodes. + */ + @NotNull + private final ObjectDictionary cachedLights; + + /** + * The map with cached audio nodes. + */ + @NotNull + private final ObjectDictionary cachedAudioNodes; + + /** + * The map with cached presentable objects. + */ + @NotNull + private final ObjectDictionary cachedPresentableObjects; + + /** + * The array of light nodes. + */ + @NotNull + private final Array lightNodes; + + /** + * The array of audio nodes. + */ + @NotNull + private final Array audioNodes; + + /** + * The array of scene presentable nodes. + */ + @NotNull + private final Array presentableNodes; + + /** + * The node for the placement of controls. + */ + @NotNull + protected final Node toolNode; + + /** + * The node for the placement of models. + */ + @NotNull + protected final Node modelNode; + + /** + * The node for the placement of lights. + */ + @NotNull + protected final Node lightNode; + + /** + * The node for the placement of audio nodes. + */ + @NotNull + protected final Node audioNode; + + /** + * The node for the placement of presentable nodes. + */ + @NotNull + private final Node presentableNode; + + /** + * Current display model. + */ + @Nullable + private M currentModel; + + /** + * Grid of the scene. + */ + @Nullable + private Node grid; + + /** + * The flag of visibility grid. + */ + private boolean showGrid; + + public AbstractSceneEditor3dPart(@NotNull T fileEditor) { + super(fileEditor); + this.cachedLights = DictionaryFactory.newObjectDictionary(); + this.cachedAudioNodes = DictionaryFactory.newObjectDictionary(); + this.cachedPresentableObjects = DictionaryFactory.newObjectDictionary(); + this.modelNode = new Node("TreeNode"); + this.modelNode.setUserData(KEY_MODEL_NODE, true); + this.toolNode = new Node("ToolNode"); + this.lightNodes = ArrayFactory.newArray(EditorLightNode.class); + this.audioNodes = ArrayFactory.newArray(EditorAudioNode.class); + this.presentableNodes = ArrayFactory.newArray(EditorPresentableNode.class); + this.lightNode = new Node("Lights"); + this.audioNode = new Node("Audio nodes"); + this.presentableNode = new Node("Presentable nodes"); + + controls.add(new AbstractSceneEditorHotKeys3dPartControl(this)); + controls.add(new PaintingSupportEditor3dPartControl<>(this)); + controls.add(new TransformationSupportEditor3dPartControl<>(this)); + controls.add(new SelectionSupportEditor3dPartControl<>(this)); + + var cameraControl = requireControl(CameraEditor3dPartControl.class); + cameraControl.setDefaultHorizontalRotation(H_ROTATION); + cameraControl.setDefaultVerticalRotation(V_ROTATION); + + modelNode.attachChild(lightNode); + modelNode.attachChild(audioNode); + modelNode.attachChild(presentableNode); + + createToolElements(); + setShowGrid(true); + } + + /** + * Create tool elements. + */ + @FromAnyThread + private void createToolElements() { + grid = createGrid(); + toolNode.attachChild(grid); + } + + @FromAnyThread + private @NotNull Node createGrid() { + + var gridNode = new Node("GridNode"); + + var gridColor = new ColorRGBA(0.4f, 0.4f, 0.4f, 0.5f); + var xColor = new ColorRGBA(1.0f, 0.1f, 0.1f, 0.5f); + var zColor = new ColorRGBA(0.1f, 1.0f, 0.1f, 0.5f); + + var gridMaterial = JmeUtils.coloredWireframeMaterial(gridColor, EditorUtils.getAssetManager()); + gridMaterial.getAdditionalRenderState() + .setBlendMode(RenderState.BlendMode.Alpha); + + var xMaterial = JmeUtils.coloredWireframeMaterial(xColor, EditorUtils.getAssetManager()); + xMaterial.getAdditionalRenderState() + .setLineWidth(5); + + var zMaterial = JmeUtils.coloredWireframeMaterial(zColor, EditorUtils.getAssetManager()); + zMaterial.getAdditionalRenderState() + .setLineWidth(5); + + var gridSize = getGridSize(); + + var grid = new Geometry("grid", new Grid(gridSize, gridSize, 1.0f)); + grid.setMaterial(gridMaterial); + grid.setQueueBucket(RenderQueue.Bucket.Transparent); + grid.setShadowMode(RenderQueue.ShadowMode.Off); + grid.setCullHint(CullHint.Never); + grid.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); + + var quad = new Quad(gridSize, gridSize); + var gridCollision = new Geometry("collision", quad); + gridCollision.setMaterial(JmeUtils.coloredWireframeMaterial(gridColor, EditorUtils.getAssetManager())); + gridCollision.setQueueBucket(RenderQueue.Bucket.Transparent); + gridCollision.setShadowMode(RenderQueue.ShadowMode.Off); + gridCollision.setCullHint(CullHint.Always); + gridCollision.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); + gridCollision.setLocalRotation(new Quaternion().fromAngles(AngleUtils.degreeToRadians(90), 0, 0)); + + gridNode.attachChild(grid); + gridNode.attachChild(gridCollision); + + // Red line for X axis + var xAxis = new Line(new Vector3f(-gridSize / 2, 0f, 0f), new Vector3f(gridSize / 2 - 1, 0f, 0f)); + + var gxAxis = new Geometry("XAxis", xAxis); + gxAxis.setModelBound(new BoundingBox()); + gxAxis.setShadowMode(RenderQueue.ShadowMode.Off); + gxAxis.setCullHint(CullHint.Never); + gxAxis.setMaterial(xMaterial); + + gridNode.attachChild(gxAxis); + + // Blue line for Z axis + var zAxis = new Line(new Vector3f(0f, 0f, -gridSize / 2), new Vector3f(0f, 0f, gridSize / 2 - 1)); + + var gzAxis = new Geometry("ZAxis", zAxis); + gzAxis.setModelBound(new BoundingBox()); + gzAxis.setShadowMode(RenderQueue.ShadowMode.Off); + gzAxis.setCullHint(CullHint.Never); + gzAxis.setMaterial(zMaterial); + + gridNode.attachChild(gzAxis); + + return gridNode; + } + + @Override + @JmeThread + public @NotNull Node getToolNode() { + return toolNode; + } + + /** + * Get the grid size. + * + * @return the grid size. + */ + @FromAnyThread + protected int getGridSize() { + return 20; + } + + /** + * Get the grid. + * + * @return the grid. + */ + @FromAnyThread + private @NotNull Node getGrid() { + return notNull(grid); + } + + /*@Override + protected void postCameraUpdate(float tpf) { + super.postCameraUpdate(tpf); + + lightNodes.forEach(EditorLightNode::updateModel); + audioNodes.forEach(EditorAudioNode::updateModel); + presentableNodes.forEach(EditorPresentableNode::updateModel); + } +*/ + + /** + * Set true if need to show a grid. + * + * @param showGrid true if need to show a grid. + */ + @JmeThread + private void setShowGrid(boolean showGrid) { + this.showGrid = showGrid; + } + + /** + * Return true if the grid is showed. + * + * @return true if the grid is showed. + */ + @JmeThread + private boolean isShowGrid() { + return showGrid; + } + + /** + * Get a geometry on a scene for a position on a screen. + * + * @param screenX the x position on screen. + * @param screenY the y position on screen. + * @return the position on a scene. + */ + @JmeThread + public @Nullable Geometry getGeometryByScreenPos(float screenX, float screenY) { + return GeomUtils.getGeometryFromScreenPos(notNull(getCurrentModel()), getCamera(), screenX, screenY); + } + + /** + * Get a position on a scene for a cursor position. + * + * @param screenX the x position on screen. + * @param screenY the y position on screen. + * @return the position on a scene. + */ + @JmeThread + public @NotNull Vector3f getScenePosByScreenPos(float screenX, float screenY) { + + var camera = getCamera(); + var currentModel = notNull(getCurrentModel()); + + var modelPoint = GeomUtils.getContactPointFromScreenPos(currentModel, camera, screenX, screenY); + var gridPoint = GeomUtils.getContactPointFromScreenPos(getGrid(), camera, screenX, screenY); + + if (modelPoint == null) { + return gridPoint == null ? Vector3f.ZERO : gridPoint; + } else if (gridPoint == null) { + return modelPoint; + } + + var distance = modelPoint.distance(camera.getLocation()); + + if (gridPoint.distance(camera.getLocation()) < distance) { + return gridPoint; + } else { + return modelPoint; + } + } + + /** + * Get a normal on a scene for a cursor position. + * + * @param screenX the x position on screen. + * @param screenY the y position on screen. + * @return the normal on the current scene or null. + */ + @JmeThread + public @Nullable Vector3f getSceneNormalByScreenPos(float screenX, float screenY) { + var camera = getCamera(); + var currentModel = notNull(getCurrentModel()); + return GeomUtils.getContactNormalFromScreenPos(currentModel, camera, screenX, screenY); + } + + /** + * Update the state of showing a scene's grid. + * + * @param showGrid true if need to show scene's grid. + */ + @FromAnyThread + public void updateShowGrid(boolean showGrid) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateShowGridInJme(showGrid)); + } + + /** + * Update the state of showing a scene's grid in jME thread. + * + * @param showGrid true if need to show scene's grid. + */ + @JmeThread + private void updateShowGridInJme(boolean showGrid) { + + if (isShowGrid() == showGrid) { + return; + } + + var grid = getGrid(); + + if (showGrid) { + toolNode.attachChild(grid); + } else { + toolNode.detachChild(grid); + } + + setShowGrid(showGrid); + } + + /** + * Notify about an attempt to change the property from jME thread. + * + * @param object the object. + * @param name the property name. + */ + @JmeThread + public void notifyPropertyPreChanged(@NotNull Object object, @NotNull String name) { + if (object instanceof Spatial) { + if (isTransformationProperty(name)) { + PRE_TRANSFORM_HANDLERS.getExtensions() + .forEach(handler -> handler.handle((Spatial) object)); + } + } + } + + /** + * Notify about property changes. + * + * @param object the object with changes. + * @param name the property name. + */ + @JmeThread + public void notifyPropertyChanged(@NotNull Object object, @NotNull String name) { + + if (object instanceof EditableProperty) { + object = ((EditableProperty) object).getObject(); + } + + if (object instanceof AudioNode) { + + getAudioNodeOpt((AudioNode) object) + .ifPresent(EditorAudioNode::sync); + + } else if (object instanceof Light) { + + getLightNodeOpt((Light) object) + .ifPresent(EditorLightNode::sync); + + } else if (object instanceof ScenePresentable) { + + getPresentableNodeOpt((ScenePresentable) object).stream() + .peek(EditorPresentableNode::sync) + .forEach(EditorPresentableNode::updateGeometry); + } + + if (object instanceof Spatial) { + if (isTransformationProperty(name)) { + var transformed = object; + POST_TRANSFORM_HANDLERS.getExtensions() + .forEach(handler -> handler.handle((Spatial) transformed)); + } + } + } + + protected boolean isTransformationProperty(@NotNull String name) { + return Messages.MODEL_PROPERTY_LOCATION.equals(name) || + Messages.MODEL_PROPERTY_SCALE.equals(name) || + Messages.MODEL_PROPERTY_ROTATION.equals(name) || + Messages.MODEL_PROPERTY_TRANSFORMATION.equals(name); + } + + /** + * Show the model in this editor. + * + * @param model the model. + */ + @FromAnyThread + public void openModel(@NotNull M model) { + ExecutorManager.getInstance() + .addJmeTask(() -> openModelInJme(model)); + } + + /** + * Show the model in this editor in jME thread. + * + * @param model the model. + */ + @JmeThread + private void openModelInJme(@NotNull M model) { + + var currentModel = getCurrentModel(); + + if (currentModel != null) { + detachPrevModel(modelNode, currentModel); + } + + NodeUtils.visitGeometry(model, geometry -> { + + var renderManager = EditorUtils.getRenderManager(); + try { + renderManager.preloadScene(geometry); + } catch (final RendererException | AssetNotFoundException | UnsupportedOperationException e) { + EditorUtils.handleException(LOGGER, this, + new RuntimeException("Found invalid material in the geometry: [" + geometry.getName() + "]. " + + "The material will be removed from the geometry.", e)); + geometry.setMaterial(EditorUtils.getDefaultMaterial()); + } + }); + + PRE_TRANSFORM_HANDLERS.getExtensions() + .forEach(handler -> handler.handle(model)); + + attachModel(model, modelNode); + + POST_TRANSFORM_HANDLERS.getExtensions() + .forEach(handler -> handler.handle(model)); + + setCurrentModel(model); + } + + @JmeThread + protected void detachPrevModel(@NotNull Node modelNode, @Nullable M currentModel) { + if (currentModel != null) { + modelNode.detachChild(currentModel); + } + } + + @JmeThread + protected void attachModel(@NotNull M model, @NotNull Node modelNode) { + modelNode.attachChild(model); + } + + /** + * Set the current model. + * + * @param currentModel the current model. + */ + @JmeThread + private void setCurrentModel(@Nullable M currentModel) { + this.currentModel = currentModel; + } + + /** + * Get the current model. + * + * @return the current model. + */ + @FromAnyThread + public @Nullable M getCurrentModel() { + return currentModel; + } + + /** + * Add the light to this editor. + * + * @param light the light. + */ + @FromAnyThread + public void addLight(@NotNull Light light) { + ExecutorManager.getInstance() + .addJmeTask(() -> addLightInJme(light)); + } + + /** + * Add the light to this editor in jME thread. + * + * @param light the light. + */ + @JmeThread + private void addLightInJme(@NotNull Light light) { + + var node = LIGHT_MODEL_TABLE.get(light.getType()); + + if (node == null) { + return; + } + + var camera = EditorUtils.getGlobalCamera(); + + var lightModel = notNull(cachedLights.get(light, () -> { + + var model = (Node) node.clone(); + model.setLocalScale(0.03F); + + var result = new EditorLightNode(camera); + result.setModel(model); + + var geometry = NodeUtils.findGeometry(model, "White"); + + if (geometry == null) { + LOGGER.warning(this, "not found geometry for the node " + geometry); + return null; + } + + var material = geometry.getMaterial(); + material.setColor("Color", light.getColor()); + + return result; + })); + + lightModel.setLight(light); + lightModel.sync(); + + lightNode.attachChild(lightModel); + lightNode.attachChild(lightModel.getModel()); + + lightNodes.add(lightModel); + } + + /** + * Move editor's camera to the location. + * + * @param location the location. + */ + @FromAnyThread + public void moveCameraTo(@NotNull Vector3f location) { + // ExecutorManager.getInstance() + // .addJmeTask(() -> getNodeForCamera().setLocalTranslation(location)); + } + + /** + * Look at the spatial. + * + * @param spatial the spatial. + */ + @FromAnyThread + public void cameraLookAt(@NotNull Spatial spatial) { + + /* var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + + var editorCamera = notNull(getEditorCamera()); + var local = LocalObjects.get(); + + float distance; + + var worldBound = spatial.getWorldBound(); + + if (worldBound != null) { + + distance = worldBound.getVolume(); + + if (worldBound instanceof BoundingBox) { + final BoundingBox boundingBox = (BoundingBox) worldBound; + distance = boundingBox.getXExtent(); + distance = Math.max(distance, boundingBox.getYExtent()); + distance = Math.max(distance, boundingBox.getZExtent()); + distance *= 2F; + } else if (worldBound instanceof BoundingSphere) { + distance = ((BoundingSphere) worldBound).getRadius() * 2F; + } + + } else { + + distance = getCamera().getLocation() + .distance(spatial.getWorldTranslation()); + } + + editorCamera.setTargetDistance(distance); + + var position = local.nextVector() + .set(spatial.getWorldTranslation()); + + getNodeForCamera().setLocalTranslation(position); + });*/ + } + + /** + * Remove the light from this editor. + * + * @param light the light. + */ + @FromAnyThread + public void removeLight(@NotNull Light light) { + ExecutorManager.getInstance() + .addJmeTask(() -> removeLightInJme(light)); + } + + /** + * Remove the light from this editor in jME thread. + * + * @param light the light. + */ + @JmeThread + private void removeLightInJme(@NotNull Light light) { + + var node = LIGHT_MODEL_TABLE.get(light.getType()); + + if (node == null) { + return; + } + + var lightModel = cachedLights.get(light); + if (lightModel == null) { + return; + } + + lightModel.setLight(null); + + lightNode.detachChild(lightModel); + lightNode.detachChild(notNull(lightModel.getModel())); + + lightNodes.fastRemove(lightModel); + } + + /** + * Add the audio node to this editor. + * + * @param audioNode the audio node. + */ + @FromAnyThread + public void addAudioNode(@NotNull AudioNode audioNode) { + ExecutorManager.getInstance() + .addJmeTask(() -> addAudioNodeInJme(audioNode)); + } + + /** + * Add the audio node to this editor in jME thread. + * + * @param audio the audio node. + */ + @JmeThread + private void addAudioNodeInJme(@NotNull AudioNode audio) { + + var audioModel = notNull(cachedAudioNodes.get(audio, () -> { + + var model = (Node) AUDIO_NODE_MODEL.clone(); + model.setLocalScale(0.01F); + + var result = new EditorAudioNode(getCamera()); + result.setModel(model); + + return result; + })); + + audioModel.setAudioNode(audio); + audioModel.sync(); + + audioNode.attachChild(audioModel); + audioNode.attachChild(audioModel.getModel()); + + audioNodes.add(audioModel); + } + + /** + * Remove the audio node from this editor. + * + * @param audio the audio node. + */ + @FromAnyThread + public void removeAudioNode(@NotNull AudioNode audio) { + ExecutorManager.getInstance() + .addJmeTask(() -> removeAudioNodeInJme(audio)); + } + + /** + * Remove the audio node from this editor in jME thread. + * + * @param audio the audio node. + */ + @JmeThread + private void removeAudioNodeInJme(@NotNull AudioNode audio) { + + var audioModel = cachedAudioNodes.get(audio); + + if (audioModel == null) { + return; + } + + audioModel.setAudioNode(null); + + audioNode.detachChild(audioModel); + audioNode.detachChild(notNull(audioModel.getModel())); + + audioNodes.fastRemove(audioModel); + } + + /** + * Add the presentable object to this editor. + * + * @param presentable the presentable object. + */ + @FromAnyThread + public void addPresentable(@NotNull ScenePresentable presentable) { + ExecutorManager.getInstance() + .addJmeTask(() -> addPresentableInJme(presentable)); + } + + /** + * Add the presentable object to this editor in jME. + * + * @param presentable the presentable object. + */ + @JmeThread + private void addPresentableInJme(@NotNull ScenePresentable presentable) { + + var node = notNull(cachedPresentableObjects.get(presentable, EditorPresentableNode::new)); + + node.setObject(presentable); + node.updateGeometry(); + node.sync(); + + var editedNode = node.getEditedNode(); + editedNode.setCullHint(CullHint.Always); + + presentableNode.attachChild(node); + presentableNode.attachChild(node.getModel()); + + node.setObject(presentable); + + presentableNodes.add(node); + } + + /** + * Remove the presentable object from this editor. + * + * @param presentable the presentable. + */ + @FromAnyThread + public void removePresentable(@NotNull ScenePresentable presentable) { + ExecutorManager.getInstance() + .addJmeTask(() -> removePresentableInJme(presentable)); + } + + /** + * Remove the presentable object from this editor in jME thread. + * + * @param presentable the presentable. + */ + @JmeThread + private void removePresentableInJme(@NotNull ScenePresentable presentable) { + + var node = cachedPresentableObjects.get(presentable); + + if (node == null) { + return; + } + + node.setObject(null); + + presentableNode.detachChild(node); + presentableNode.detachChild(notNull(node.getModel())); + + presentableNodes.fastRemove(node); + } + + /** + * Get a light node for the light. + * + * @param light the light. + * @return the light node or null. + */ + @FromAnyThread + public @Nullable EditorLightNode getLightNode(@NotNull Light light) { + return lightNodes.findAny(light, + (node, toCheck) -> node.getLight() == toCheck); + } + + /** + * Get an optional of a light node for the light. + * + * @param light the light. + * @return the optional value. + */ + @FromAnyThread + public @NotNull Optional getLightNodeOpt(@NotNull Light light) { + return Optional.ofNullable(getLightNode(light)); + } + + /** + * Get a light node for the model. + * + * @param model the model. + * @return the light node or null. + */ + @FromAnyThread + public @Nullable EditorLightNode getLightNode(@NotNull Spatial model) { + return lightNodes.findAny(model, + (node, toCheck) -> node.getModel() == toCheck); + } + + /** + * Get an editor audio node of the audio node. + * + * @param audioNode the audio node. + * @return the editor audio node or null. + */ + @FromAnyThread + public @Nullable EditorAudioNode getAudioNode(@NotNull AudioNode audioNode) { + return audioNodes.findAny(audioNode, + (node, toCheck) -> node.getAudioNode() == toCheck); + } + + /** + * Get an optional of an editor audio node for the audio node. + * + * @param audioNode the audio node. + * @return the optional value. + */ + @FromAnyThread + public @NotNull Optional getAudioNodeOpt(@NotNull AudioNode audioNode) { + return Optional.ofNullable(getAudioNode(audioNode)); + } + + /** + * Get an editor audio node for the model. + * + * @param model the model. + * @return the editor audio node or null. + */ + @FromAnyThread + public @Nullable EditorAudioNode getAudioNode(@NotNull Spatial model) { + return audioNodes.findAny(model, + (node, toCheck) -> node.getModel() == toCheck); + } + + /** + * Get an optional of an editor audio node for the model. + * + * @param model the model. + * @return the optional value. + */ + @FromAnyThread + public @NotNull Optional getAudioNodeOpt(@NotNull Spatial model) { + return Optional.ofNullable(getAudioNode(model)); + } + + /** + * Get an editor presentable node for the presentable object. + * + * @param presentable the presentable object. + * @return the editor presentable node or null. + */ + @FromAnyThread + public @Nullable EditorPresentableNode getPresentableNode(@NotNull ScenePresentable presentable) { + return presentableNodes.findAny(presentable, + (node, toCheck) -> node.getObject() == toCheck); + } + + /** + * Get an optional of an editor presentable node for the presentable object. + * + * @param presentable the presentable object. + * @return the optional value. + */ + @FromAnyThread + public @NotNull Optional getPresentableNodeOpt(@NotNull ScenePresentable presentable) { + return Optional.ofNullable(getPresentableNode(presentable)); + } + + /** + * Get an editor presentable node for the model. + * + * @param model the model. + * @return the editor presentable node or null. + */ + @FromAnyThread + public @Nullable EditorPresentableNode getPresentableNode(@NotNull Spatial model) { + return presentableNodes.findAny(model, + (node, toCheck) -> node.getModel() == toCheck); + } +/* + @Override + @JmeThread + protected void notifyChangedCameraSettings( + @NotNull Vector3f cameraLocation, + float hRotation, + float vRotation, + float targetDistance, + float cameraFlySpeed + ) { + super.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraFlySpeed); + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> + fileEditor.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraFlySpeed)); + } +*/ + @Override + @JmeThread + public @NotNull Camera getCamera() { + return EditorUtils.getGlobalCamera(); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/SceneEditor3dPart.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/SceneEditor3dPart.java new file mode 100644 index 00000000..b128b33d --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/SceneEditor3dPart.java @@ -0,0 +1,295 @@ +package com.ss.builder.jme.editor.part3d.impl.scene; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_FXAA_FILTER; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TONEMAP_FILTER; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_FILTER_FXAA; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_FILTER_TONEMAP; +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.scene.Node; +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.config.EditorConfig; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.editor.impl.scene.SceneFileEditor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link AbstractSceneEditor3dPart} for the {@link SceneFileEditor}. + * + * @author JavaSaBr + */ +public class SceneEditor3dPart extends AbstractSceneEditor3dPart { + + /** + * The flag of showing light models. + */ + private boolean lightShowed; + + /** + * The flag of showing audio models. + */ + private boolean audioShowed; + + public SceneEditor3dPart(@NotNull SceneFileEditor fileEditor) { + super(fileEditor); + + this.lightShowed = true; + this.audioShowed = true; + + stateNode.attachChild(modelNode); + stateNode.attachChild(toolNode); + } + + @Override + @JmeThread + protected int getGridSize() { + return 1000; + } + + @Override + @JmeThread + protected void attachModel(@NotNull SceneNode model, @NotNull Node modelNode) { + } + + @Override + @JmeThread + protected void detachPrevModel(@NotNull Node modelNode, @Nullable SceneNode currentModel) { + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + + var currentModel = getCurrentModel(); + + if (currentModel != null) { + modelNode.attachChild(currentModel); + } + + var jmeApplication = JmeApplication.getInstance(); + var fxaaFilter = jmeApplication.getFXAAFilter(); + var toneMapFilter = jmeApplication.getToneMapFilter(); + + fxaaFilter.setEnabled(false); + toneMapFilter.setEnabled(false); + } + + @Override + @JmeThread + public void cleanup() { + super.cleanup(); + + var currentModel = getCurrentModel(); + + if (currentModel != null) { + modelNode.detachChild(currentModel); + } + + var editorConfig = EditorConfig.getInstance(); + var jmeApplication = JmeApplication.getInstance(); + + var fxaaFilter = jmeApplication.getFXAAFilter(); + fxaaFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER)); + + var toneMapFilter = jmeApplication.getToneMapFilter(); + toneMapFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER)); + } + + /** + * Add the scene app state to this editor. + * + * @param appState the scene app state. + */ + @FromAnyThread + public void addAppState(@NotNull SceneAppState appState) { + ExecutorManager.getInstance() + .addJmeTask(() -> addAppStateInJme(appState)); + } + + /** + * Add a scene app state to this editor in jME thread. + * + * @param appState the scene app state. + */ + @JmeThread + private void addAppStateInJme(@NotNull SceneAppState appState) { + var stateManager = EditorUtils.getStateManager(); + stateManager.attach(appState); + } + + /** + * Remove the scene app state from this editor. + * + * @param appState the scene app state. + */ + @FromAnyThread + public void removeAppState(@NotNull SceneAppState appState) { + ExecutorManager.getInstance() + .addJmeTask(() -> removeAppStateInJme(appState)); + } + + /** + * Remove the scene app state from this editor in jME thread. + * + * @param appState the scene app state. + */ + @JmeThread + private void removeAppStateInJme(@NotNull SceneAppState appState) { + var stateManager = EditorUtils.getStateManager(); + stateManager.detach(appState); + } + + /** + * Add the scene filter to this editor. + * + * @param sceneFilter the scene filter. + */ + @FromAnyThread + public void addFilter(@NotNull SceneFilter sceneFilter) { + ExecutorManager.getInstance() + .addJmeTask(() -> addFilterImpl(sceneFilter)); + } + + /** + * Add the scene filter to this editor in jME thread. + * + * @param sceneFilter the scene filter. + */ + @JmeThread + private void addFilterImpl(@NotNull SceneFilter sceneFilter) { + var postProcessor = EditorUtils.getGlobalFilterPostProcessor(); + postProcessor.addFilter(sceneFilter.get()); + } + + /** + * Remove the scene filter from this editor. + * + * @param sceneFilter the scene filter. + */ + @FromAnyThread + public void removeFilter(@NotNull SceneFilter sceneFilter) { + ExecutorManager.getInstance() + .addJmeTask(() -> removeFilterInJme(sceneFilter)); + } + + /** + * Remove the scene filter from this editor in jME thread. + * + * @param sceneFilter the scene filter. + */ + @JmeThread + private void removeFilterInJme(@NotNull SceneFilter sceneFilter) { + var postProcessor = EditorUtils.getGlobalFilterPostProcessor(); + postProcessor.removeFilter(sceneFilter.get()); + } + + /** + * Return true if need to show light models. + * + * @return true if need to show light models. + */ + @JmeThread + private boolean isLightShowed() { + return lightShowed; + } + + /** + * Set true if need to show light models. + * + * @param lightShowed true if need to show light models. + */ + @JmeThread + private void setLightShowed(boolean lightShowed) { + this.lightShowed = lightShowed; + } + + /** + * Return true if need to show audio models. + * + * @return true if need to show audio models. + */ + @JmeThread + private boolean isAudioShowed() { + return audioShowed; + } + + /** + * Set true if need to show audio models. + * + * @param audioShowed true if need to show audio models. + */ + @JmeThread + private void setAudioShowed(boolean audioShowed) { + this.audioShowed = audioShowed; + } + + /** + * Change light showing. + * + * @param showed the showed + */ + @FromAnyThread + public void updateLightShowed(boolean showed) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateLightShowedInJme(showed)); + } + + /** + * Change light showing in jME thread. + * + * @param showed the showed. + */ + @JmeThread + private void updateLightShowedInJme(boolean showed) { + + if (showed == isLightShowed()) { + return; + } + + if (showed) { + modelNode.attachChild(lightNode); + } else { + modelNode.detachChild(lightNode); + } + + setLightShowed(showed); + } + + /** + * Change audio showing. + * + * @param showed the showed. + */ + @FromAnyThread + public void updateAudioShowed(boolean showed) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateAudioShowedInJme(showed)); + } + + /** + * The process to change audio showing. + */ + @JmeThread + private void updateAudioShowedInJme(boolean showed) { + + if (showed == isAudioShowed()) { + return; + } + + if (showed) { + modelNode.attachChild(audioNode); + } else { + modelNode.detachChild(audioNode); + } + + setAudioShowed(showed); + } +} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java similarity index 86% rename from src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java rename to src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java index fcd78de1..8497fc0d 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java @@ -1,14 +1,16 @@ -package com.ss.editor.part3d.editor.impl.scene.handler; +package com.ss.builder.jme.editor.part3d.impl.scene.handler; import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.math.Vector3f; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.dictionary.DictionaryFactory; import com.ss.rlib.common.util.dictionary.ObjectDictionary; import org.jetbrains.annotations.NotNull; @@ -29,7 +31,7 @@ public class ApplyScaleToPhysicsControlsHandler { @FromAnyThread protected static boolean isModelRoot(@NotNull final Spatial spatial) { final Node parent = spatial.getParent(); - return parent == null || parent.getUserData(AbstractSceneEditor3DPart.KEY_MODEL_NODE) != null; + return parent == null || parent.getUserData(AbstractSceneEditor3dPart.KEY_MODEL_NODE) != null; } /** diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/DisableControlsTransformationHandler.java similarity index 89% rename from src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java rename to src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/DisableControlsTransformationHandler.java index 0a6d2bf9..ab57aa77 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/DisableControlsTransformationHandler.java @@ -1,4 +1,4 @@ -package com.ss.editor.part3d.editor.impl.scene.handler; +package com.ss.builder.jme.editor.part3d.impl.scene.handler; import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; @@ -6,9 +6,10 @@ import com.jme3.bullet.control.RigidBodyControl; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.dictionary.DictionaryFactory; import com.ss.rlib.common.util.dictionary.ObjectDictionary; diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/PhysicsControlTransformationHandler.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/PhysicsControlTransformationHandler.java new file mode 100644 index 00000000..ef1fae6f --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/PhysicsControlTransformationHandler.java @@ -0,0 +1,22 @@ +package com.ss.builder.jme.editor.part3d.impl.scene.handler; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.util.JmbExtUtils; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import org.jetbrains.annotations.NotNull; + +/** + * The handler to updated positions for physics controls on spatial transformations. + * + * @author JavaSaBr + */ +public class PhysicsControlTransformationHandler implements AbstractSceneEditor3dPart.TransformationHandler { + + @Override + @JmeThread + public void handle(@NotNull Spatial object) { + JmbExtUtils.resetPhysicsControlPositions(object); + } +} diff --git a/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java new file mode 100644 index 00000000..e02515af --- /dev/null +++ b/src/main/java/com/ss/builder/jme/editor/part3d/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java @@ -0,0 +1,32 @@ +package com.ss.builder.jme.editor.part3d.impl.scene.handler; + +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.impl.scene.AbstractSceneEditor3dPart; +import com.ss.builder.util.ControlUtils; +import com.ss.builder.util.NodeUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The handler to reactivate enabled physics controls during transforming spatial. + * + * @author JavaSaBr + */ +public class ReactivatePhysicsControlsTransformationHandler implements AbstractSceneEditor3dPart.TransformationHandler { + + @Override + @JmeThread + public void handle(@NotNull Spatial object) { + NodeUtils.children(object) + .flatMap(ControlUtils::controls) + .filter(RigidBodyControl.class::isInstance) + .map(RigidBodyControl.class::cast) + .filter(RigidBodyControl::isEnabled) + .filter(control -> Float.compare(control.getMass(), 0.0F) != 0) + .filter(control -> !control.isActive()) + .forEach(PhysicsRigidBody::activate); + } +} diff --git a/src/main/java/com/ss/builder/jme/filter/EditorFXAAFilter.java b/src/main/java/com/ss/builder/jme/filter/EditorFXAAFilter.java new file mode 100644 index 00000000..97638bbe --- /dev/null +++ b/src/main/java/com/ss/builder/jme/filter/EditorFXAAFilter.java @@ -0,0 +1,22 @@ +package com.ss.builder.jme.filter; + +import com.jme3.post.filters.FXAAFilter; +import com.jme3.texture.Texture; +import org.jetbrains.annotations.NotNull; + +/** + * The changed implementation of {@link FXAAFilter} for this editor. + * + * @author JavaSaBr + */ +public class EditorFXAAFilter extends FXAAFilter { + + @Override + protected boolean isRequiresDepthTexture() { + return true; + } + + @Override + protected void setDepthTexture(@NotNull final Texture depthTexture) { + } +} diff --git a/src/main/java/com/ss/builder/manager/AsyncEventManager.java b/src/main/java/com/ss/builder/manager/AsyncEventManager.java new file mode 100644 index 00000000..ac4ae26a --- /dev/null +++ b/src/main/java/com/ss/builder/manager/AsyncEventManager.java @@ -0,0 +1,356 @@ +package com.ss.builder.manager; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.event.ConsumableEvent; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ArrayUtils; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.array.ConcurrentArray; +import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.event.EventType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * The class to manage async events. + * + * @author JavaSaBr + */ +public class AsyncEventManager { + + private static final Logger LOGGER = LoggerManager.getLogger(AsyncEventManager.class); + + /** + * Builder to build a combined async events handler. + * + * @author JavaSaBr + */ + public static class SingleAsyncEventHandlerBuilder { + + /** + * Create a builder for the event type. + * + * @param eventType the event type. + * @return the new builder. + */ + @FromAnyThread + public static @NotNull SingleAsyncEventHandlerBuilder of(@NotNull EventType eventType) { + return new SingleAsyncEventHandlerBuilder(eventType); + } + + /** + * The list of listened event types. + */ + @NotNull + private final EventType eventType; + + /** + * The result handler. + */ + @NotNull + private final Array handlers; + + public SingleAsyncEventHandlerBuilder(@NotNull EventType eventType) { + this.handlers = ArrayFactory.newArray(Runnable.class); + this.eventType = ClassUtils.unsafeCast(eventType); + } + + /** + * Add the handler. + * + * @param handler the handler. + * @return this builder. + */ + @FromAnyThread + public @NotNull SingleAsyncEventHandlerBuilder add(@NotNull Runnable handler) { + handlers.add(handler); + return this; + } + + @FromAnyThread + public void buildAndRegister() { + + if (handlers.isEmpty()) { + throw new IllegalStateException("The list of handlers should not be empty."); + } + + var resultHandler = new CombinedEventHandler(Array.of(eventType), handlers); + var eventManager = getInstance(); + + var eventTypesSet = resultHandler.eventTypesSet; + eventTypesSet.forEach(eventType -> + eventManager.addEventHandler(eventType, resultHandler)); + } + } + + /** + * Builder to build a combined async events handler. + * + * @author JavaSaBr + */ + public static class CombinedAsyncEventHandlerBuilder { + + /** + * Create a builder for the handler. + * + * @param handler the result handler. + * @return the new builder. + */ + @FromAnyThread + public static @NotNull CombinedAsyncEventHandlerBuilder of(@NotNull Runnable handler) { + return new CombinedAsyncEventHandlerBuilder(handler); + } + + /** + * The list of listened event types. + */ + @NotNull + private final Array> eventTypes; + + /** + * The result handler. + */ + @NotNull + private final Runnable handler; + + public CombinedAsyncEventHandlerBuilder(@NotNull Runnable handler) { + this.handler = handler; + this.eventTypes = ArrayFactory.newArray(EventType.class); + } + + /** + * Add listening the additional event type. + * + * @param eventType the additional event type. + * @return this builder. + */ + @FromAnyThread + public @NotNull CombinedAsyncEventHandlerBuilder add(@NotNull EventType eventType) { + return add(eventType, 1); + } + + /** + * Add listening the additional event type. + * + * @param eventType the additional event type. + * @param count the count of expected events of the type. + * @return this builder. + */ + @FromAnyThread + public @NotNull CombinedAsyncEventHandlerBuilder add(@NotNull EventType eventType, int count) { + + for (int i = 0; i < count; i++) { + eventTypes.add(ClassUtils.unsafeCast(eventType)); + } + + return this; + } + + @FromAnyThread + public void buildAndRegister() { + + if (eventTypes.isEmpty()) { + throw new IllegalStateException("The list of listened events should not be empty."); + } + + var resultHandler = new CombinedEventHandler(eventTypes, Array.of(handler)); + var eventManager = getInstance(); + + var eventTypesSet = resultHandler.eventTypesSet; + eventTypesSet.forEach(eventType -> + eventManager.addEventHandler(eventType, resultHandler)); + } + } + + private static class CombinedEventHandler implements EventHandler { + + @NotNull + private final ConcurrentArray> eventTypes; + + @NotNull + private final Array> eventTypesSet; + + @NotNull + private final Array handlers; + + public CombinedEventHandler(@NotNull Array> eventTypes, @NotNull Array handlers) { + this.eventTypes = ArrayFactory.newConcurrentStampedLockArray(EventType.class); + this.eventTypes.addAll(eventTypes); + this.eventTypesSet = ArrayFactory.newArraySet(EventType.class); + this.eventTypesSet.addAll(eventTypes); + this.handlers = handlers; + } + + @Override + public void handle(@NotNull Event event) { + + ArrayUtils.runInWriteLock(eventTypes, event.getEventType(), Array::remove); + + if (!eventTypes.isEmpty()) { + return; + } + + handlers.forEach(Runnable::run); + + var eventManager = getInstance(); + + eventTypesSet.forEach(eventType -> + eventManager.removeEventHandler(eventType, this)); + } + + @Override + public String toString() { + + if (handlers.size() == 1) { + return handlers.first().getClass().getSimpleName(); + } + + return handlers.toString(); + } + } + + private static final AsyncEventManager INSTANCE = new AsyncEventManager(); + + @FromAnyThread + public static @NotNull AsyncEventManager getInstance() { + return INSTANCE; + } + + /** + * The table of event handlers. + */ + @NotNull + private final ConcurrentObjectDictionary, + ConcurrentArray>> eventHandlers; + + public AsyncEventManager() { + this.eventHandlers = DictionaryFactory.newConcurrentAtomicObjectDictionary(); + } + + /** + * Add a new event handler. + * + * @param eventType the event type. + * @param eventHandler the event handler. + */ + @FromAnyThread + public void addEventHandler( + @NotNull EventType eventType, + @NotNull EventHandler eventHandler + ) { + + LOGGER.debug(eventType, eventHandler, + (type, handler) -> "Register the handler " + handler + " for the event type " + type); + + var allHandlers = getEventHandlers(); + var handlers = allHandlers.getInReadLock(eventType, ObjectDictionary::get); + + if (handlers != null) { + handlers.runInWriteLock(eventHandler, Collection::add); + return; + } + + allHandlers.runInWriteLock(dictionary -> { + var newHandlers = dictionary.getOrCompute(eventType, ConcurrentArray.supplier(EventHandler.class)); + newHandlers.runInWriteLock(eventHandler, Collection::add); + }); + } + + /** + * Remove an old event handler. + * + * @param eventType the event type. + * @param eventHandler the event handler. + */ + @FromAnyThread + public void removeEventHandler( + @NotNull EventType eventType, + @NotNull EventHandler eventHandler + ) { + + LOGGER.debug(eventType, eventHandler, + (type, handler) -> "Remove the handler " + handler + " for the event type " + type); + + var handlers = getEventHandlers() + .getInReadLock(eventType, ObjectDictionary::get); + + if (handlers != null) { + handlers.runInWriteLock(eventHandler, Collection::remove); + } + } + + /** + * Get the table of event handlers. + * + * @return the table of event handlers. + */ + @FromAnyThread + private @NotNull ConcurrentObjectDictionary, + ConcurrentArray>> getEventHandlers() { + return eventHandlers; + } + + /** + * Notify about a new event. + * + * @param event the new event. + */ + @FromAnyThread + public void notify(@NotNull Event event) { + ExecutorManager.getInstance() + .addBackgroundTask(() -> notifyImpl(event)); + } + + /** + * The process of handling a new event. + */ + @BackgroundThread + private void notifyImpl(@NotNull Event event) { + + LOGGER.debug(event, e -> "Received the event " + e); + + var eventHandlers = getEventHandlers(); + + for (EventType eventType = event.getEventType(); + eventType != null; + eventType = eventType.getSuperType()) { + + var handlers = eventHandlers.getInReadLock(eventType, ObjectDictionary::get); + + + if (handlers == null || handlers.isEmpty()) { + continue; + } + + handlers.runInReadLock(event, (array, toHandle) -> { + for (var eventHandler : array) { + ExecutorManager.getInstance() + .addBackgroundTask(() -> notifyImpl(event, eventHandler)); + } + }); + } + + if (event instanceof ConsumableEvent && !event.isConsumed()) { + ExecutorManager.getInstance() + .addBackgroundTask(() -> notifyImpl(event)); + } + } + + @BackgroundThread + private void notifyImpl(@NotNull Event event, @NotNull EventHandler eventHandler) { + + LOGGER.debug(event, eventHandler, + (e, handler) -> e + " -> " + handler); + + eventHandler.handle(ClassUtils.unsafeCast(event)); + } +} diff --git a/src/main/java/com/ss/builder/manager/ClasspathManager.java b/src/main/java/com/ss/builder/manager/ClasspathManager.java new file mode 100644 index 00000000..b92c7b3e --- /dev/null +++ b/src/main/java/com/ss/builder/manager/ClasspathManager.java @@ -0,0 +1,554 @@ +package com.ss.builder.manager; + +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_USER_CLASSES_FOLDER; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_USER_LIBRARY_FOLDER; +import com.ss.builder.FileExtensions; +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.impl.ClasspathReloadedEvent; +import com.ss.builder.fx.event.impl.CoreClassesScannedEvent; +import com.ss.builder.fx.event.impl.JmeContextCreatedEvent; +import com.ss.builder.fx.event.impl.ManagersInitializedEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.classpath.ClassPathScanner; +import com.ss.rlib.common.classpath.ClassPathScannerFactory; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +/** + * The class to manage classpath. + * + * @author JavaSaBr + */ +public class ClasspathManager { + + private static final Logger LOGGER = LoggerManager.getLogger(ClasspathManager.class); + + public enum Scope { + CORE, + CUSTOM, + PLUGINS, + LOCAL_LIBRARIES, + LOCAL_CLASSES; + + public static final Set ONLY_CORE = EnumSet.of(CORE); + public static final Set ALL = EnumSet.allOf(Scope.class); + public static final Set CORE_AND_CUSTOM_AND_LOCAL = + EnumSet.of(CORE, CUSTOM, LOCAL_CLASSES, LOCAL_LIBRARIES); + } + + private static final String[] JAR_EXTENSIONS = + ArrayFactory.toArray(FileExtensions.JAVA_LIBRARY); + + public static final Array CORE_LIBRARIES_NAMES = Array.of( + "jme3-core", + "jme3-terrain", + "jme3-effects", + "jme3-testdata", + "jme3-plugins", + "tonegod", + "jmonkeybuilder" + ); + + @Nullable + private static ClasspathManager instance; + + @FromAnyThread + public static @NotNull ClasspathManager getInstance() { + if (instance == null) instance = new ClasspathManager(); + return instance; + } + + /** + * The libraries class loader. + */ + @NotNull + private final AtomicReference librariesLoader; + + /** + * The classes class loader. + */ + @NotNull + private final AtomicReference classesLoader; + + /** + * The custom classpath scanner. + */ + @NotNull + private final AtomicReference customScanner; + + /** + * The local libraries scanner. + */ + @NotNull + private final AtomicReference localLibrariesScanner; + + /** + * The local classes scanner. + */ + @NotNull + private final AtomicReference localClassesScanner; + + /** + * The local libraries class loader. + */ + @NotNull + private final AtomicReference localLibrariesLoader; + + /** + * The local classes class loader. + */ + @NotNull + private final AtomicReference localClassesLoader; + + /** + * The core classpath scanner. + */ + @NotNull + private volatile ClassPathScanner coreScanner; + + private ClasspathManager() { + InitializeManager.valid(getClass()); + + this.coreScanner = ClassPathScannerFactory.newDefaultScanner(); + this.librariesLoader = new AtomicReference<>(); + this.classesLoader = new AtomicReference<>(); + this.customScanner = new AtomicReference<>(); + this.localLibrariesScanner = new AtomicReference<>(); + this.localClassesScanner = new AtomicReference<>(); + this.localLibrariesLoader = new AtomicReference<>(); + this.localClassesLoader = new AtomicReference<>(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::scanCoreClasses) + .add(ManagersInitializedEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::reload) + .add(CoreClassesScannedEvent.EVENT_TYPE) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + + LOGGER.info("initialized."); + } + + /** + * Scan core classes in background. + */ + @BackgroundThread + private void scanCoreClasses() { + + var coreScanner = ClassPathScannerFactory.newManifestScanner(JmeApplication.class, "Class-Path"); + coreScanner.setUseSystemClasspath(true); + coreScanner.scan(this::filterCoreLibraries); + + this.coreScanner = coreScanner; + + AsyncEventManager.getInstance() + .notify(new CoreClassesScannedEvent()); + + LOGGER.info("scanned core classes."); + } + + @BackgroundThread + private boolean filterCoreLibraries(@NotNull String path) { + + if (Files.isDirectory(Paths.get(path))) { + return true; + } else if (!CORE_LIBRARIES_NAMES.anyMatch(path, (pattern, pth) -> pth.contains(pattern))) { + return false; + } else if (path.contains("natives")) { + return false; + } else { + return !path.contains("sources") && !path.contains("javadoc"); + } + } + + /** + * Reload custom classes and libraries. + */ + @BackgroundThread + private void reloadInBackground() { + + var userLibrariesLoader = createUserLibrariesLoader(); + var userClassesLoader = createUserClassesLoader(userLibrariesLoader); + var currentScanner = getCustomScanner(); + try { + + if (userLibrariesLoader == null && userClassesLoader == null) { + customScanner.compareAndSet(currentScanner, null); + return; + } + + var classLoader = userClassesLoader == null ? userLibrariesLoader : userClassesLoader; + var scanner = ClassPathScannerFactory.newDefaultScanner(classLoader); + var urls = Array.ofType(URL.class); + + if (userLibrariesLoader != null) { + urls.addAll(userLibrariesLoader.getURLs()); + } + + if (userClassesLoader != null) { + urls.addAll(userClassesLoader.getURLs()); + } + + var paths = urls.stream() + .map(url -> Utils.get(url, URL::toURI)) + .map(Paths::get) + .map(Path::toString) + .toArray(String[]::new); + + scanner.addAdditionalPaths(paths); + scanner.setUseSystemClasspath(false); + scanner.scan(); + + customScanner.compareAndSet(currentScanner, scanner); + + } finally { + updateClassLoader(userLibrariesLoader, getLibrariesLoader(), librariesLoader); + updateClassLoader(userClassesLoader, getClassesLoader(), classesLoader); + + AsyncEventManager.getInstance() + .notify(new ClasspathReloadedEvent()); + + LOGGER.info("reloaded."); + } + } + + /** + * Get all available resources from classpath. + * + * @return the list of resources. + */ + public @NotNull Array getAllResources() { + return coreScanner.getFoundResources(); + } + + /** + * Reload custom classes and libraries. + */ + @FromAnyThread + public void reload() { + ExecutorManager.getInstance() + .addBackgroundTask(this::reloadInBackground); + } + + /** + * Prepare a relevant user's libraries loader. + */ + @BackgroundThread + private @Nullable URLClassLoader createUserLibrariesLoader() { + + var path = EditorConfig.getInstance() + .getFile(PREF_USER_LIBRARY_FOLDER); + + if (path == null) { + return null; + } + + var urls = FileUtils.getFiles(path, false, JAR_EXTENSIONS) + .stream() + .map(FileUtils::getUrl) + .toArray(URL[]::new); + + return new URLClassLoader(urls, getClass().getClassLoader()); + } + + /** + * Update compiled classes loader. + */ + @FromAnyThread + private @Nullable URLClassLoader createUserClassesLoader(@Nullable ClassLoader userLibrariesLoader) { + + var path = EditorConfig.getInstance() + .getFile(PREF_USER_CLASSES_FOLDER); + + if (path == null) { + return null; + } + + var folders = Array.ofType(Path.class); + + FileUtils.forEachR(path, folders, + Files::isDirectory, + Collection::add); + + var urls = folders.stream() + .map(FileUtils::getUrl) + .toArray(URL[]::new); + + var parent = userLibrariesLoader == null ? + getClass().getClassLoader() : userLibrariesLoader; + + return new URLClassLoader(urls, parent); + } + + /** + * Update class loader. + */ + @BackgroundThread + private void updateClassLoader( + @Nullable URLClassLoader newLoader, + @Nullable URLClassLoader currentLoader, + @NotNull AtomicReference reference + ) { + + if (!reference.compareAndSet(currentLoader, newLoader)) { + return; + } + + var assetManager = EditorUtils.getAssetManager(); + + if (currentLoader != null) { + ExecutorManager.getInstance() + .addJmeTask(() -> assetManager.removeClassLoader(currentLoader)); + } + + if (newLoader != null) { + ExecutorManager.getInstance() + .addJmeTask(() -> assetManager.addClassLoader(newLoader)); + } + } + + /** + * Load local libraries. + */ + @FromAnyThread + public @NotNull ClasspathManager loadLocalLibraries(@NotNull Array libraries) { + + var currentClassLoader = getLocalLibrariesLoader(); + var newClassLoader = ClassPathScanner.NULL_CLASS_LOADER; + var currentScanner = getLocalLibrariesScanner(); + var newScanner = ClassPathScanner.NULL_SCANNER; + + try { + + if (libraries.isEmpty()) { + return this; + } + + var urlArray = libraries.stream() + .map(FileUtils::getUrl) + .toArray(URL[]::new); + + newClassLoader = new URLClassLoader(urlArray, getClass().getClassLoader()); + + var paths = Arrays.stream(newClassLoader.getURLs()) + .map(url -> Utils.get(url, URL::toURI)) + .map(Paths::get) + .map(Path::toString) + .toArray(String[]::new); + + var scanner = ClassPathScannerFactory.newDefaultScanner(newClassLoader); + scanner.addAdditionalPaths(paths); + scanner.setUseSystemClasspath(false); + scanner.scan(); + + } finally { + updateClassLoader(newClassLoader, currentClassLoader, localLibrariesLoader); + localLibrariesScanner.compareAndSet(currentScanner, newScanner); + } + + return this; + } + + /** + * Load local classes. + */ + @FromAnyThread + public @NotNull ClasspathManager loadLocalClasses(@Nullable Path output) { + + var currentClassLoader = getLocalClassesLoader(); + var newClassLoader = ClassPathScanner.NULL_CLASS_LOADER; + var currentScanner = getLocalClassesScanner(); + var newScanner = ClassPathScanner.NULL_SCANNER; + + try { + + if (output == null || !Files.exists(output)) { + return this; + } + + var folders = Array.ofType(Path.class); + + FileUtils.forEachR(output, folders, + Files::isDirectory, + Collection::add); + + var urlArray = folders.stream() + .map(FileUtils::getUrl) + .toArray(URL[]::new); + + var librariesLoader = getLocalLibrariesLoader(); + var parent = librariesLoader == null? getClass().getClassLoader() : librariesLoader; + + newClassLoader = new URLClassLoader(urlArray, parent); + + var paths = Arrays.stream(newClassLoader.getURLs()) + .map(url -> Utils.get(url, URL::toURI)) + .map(Paths::get) + .map(Path::toString) + .toArray(String[]::new); + + var scanner = ClassPathScannerFactory.newDefaultScanner(newClassLoader); + scanner.addAdditionalPaths(paths); + scanner.setUseSystemClasspath(false); + scanner.scan(); + + } finally { + updateClassLoader(newClassLoader, currentClassLoader, localClassesLoader); + localClassesScanner.compareAndSet(currentScanner, newScanner); + } + + return this; + } + + /** + * Get the library loader. + * + * @return the library loader. + */ + @FromAnyThread + public @Nullable URLClassLoader getLibrariesLoader() { + return librariesLoader.get(); + } + + /** + * Get the classes loader. + * + * @return the classes loader. + */ + @FromAnyThread + public @Nullable URLClassLoader getClassesLoader() { + return classesLoader.get(); + } + + /** + * Get the local libraries class loader. + * + * @return the local libraries class loader. + */ + @FromAnyThread + private @Nullable URLClassLoader getLocalLibrariesLoader() { + return localLibrariesLoader.get(); + } + + /** + * Get the local classes class loader. + * + * @return the local classes class loader. + */ + @FromAnyThread + private @Nullable URLClassLoader getLocalClassesLoader() { + return localClassesLoader.get(); + } + + /** + * Find all implementations of the interface class. + * + * @param the type of an interface. + * @param interfaceClass the interface class. + * @return the list of all available implementations. + */ + @FromAnyThread + public @NotNull Array> findImplements(@NotNull final Class interfaceClass) { + return findImplements(interfaceClass, Scope.ONLY_CORE); + } + + /** + * Get the custom scanner. + * + * @return the custom scanner. + */ + @FromAnyThread + private @Nullable ClassPathScanner getCustomScanner() { + return customScanner.get(); + } + + /** + * Get the local libraries scanner. + * + * @return the local libraries scanner. + */ + @FromAnyThread + private @Nullable ClassPathScanner getLocalLibrariesScanner() { + return localLibrariesScanner.get(); + } + + /** + * Get the local classes scanner. + * + * @return the local classes scanner. + */ + @FromAnyThread + private @Nullable ClassPathScanner getLocalClassesScanner() { + return localClassesScanner.get(); + } + + /** + * Find all implementations of the interface class. + * + * @param the type of an interface. + * @param interfaceClass the interface class. + * @param scope the scope. + * @return the list of all available implementations. + */ + @FromAnyThread + public @NotNull Array> findImplements( + @NotNull Class interfaceClass, + @NotNull Set scope + ) { + + var result = Array.>ofType(Class.class); + + if (scope.contains(Scope.CORE)) { + coreScanner.findImplements(result, interfaceClass); + } + + var customScanner = getCustomScanner(); + + if (customScanner != null && scope.contains(Scope.CUSTOM)) { + customScanner.findImplements(result, interfaceClass); + } + + var localLibrariesScanner = getLocalLibrariesScanner(); + + if (localLibrariesScanner != null && scope.contains(Scope.LOCAL_LIBRARIES)) { + localLibrariesScanner.findImplements(result, interfaceClass); + } + + var localClassesScanner = getLocalClassesScanner(); + + if (localClassesScanner != null && scope.contains(Scope.LOCAL_CLASSES)) { + localClassesScanner.findImplements(result, interfaceClass); + } + + if (scope.contains(Scope.PLUGINS)) { + PluginManager.getInstance() + .handlePluginsNow(plugin -> plugin.getContainer() + .getScanner() + .findImplements(result, interfaceClass)); + } + + return result; + } +} diff --git a/src/main/java/com/ss/builder/manager/ExecutorManager.java b/src/main/java/com/ss/builder/manager/ExecutorManager.java new file mode 100644 index 00000000..8cb8252d --- /dev/null +++ b/src/main/java/com/ss/builder/manager/ExecutorManager.java @@ -0,0 +1,132 @@ +package com.ss.builder.manager; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.executor.EditorTaskExecutor; +import com.ss.builder.executor.impl.FxEditorTaskExecutor; +import com.ss.builder.executor.impl.JmeThreadExecutor; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * The class to manage executing some tasks in the some threads. + * + * @author JavaSaBr + */ +public class ExecutorManager { + + private static final Logger LOGGER = LoggerManager.getLogger(ExecutorManager.class); + + private static ExecutorManager instance; + + public static @NotNull ExecutorManager getInstance() { + if (instance == null) instance = new ExecutorManager(); + return instance; + } + + /** + * The service to execute tasks using schedule. + */ + @NotNull + private final ScheduledExecutorService scheduledExecutorService; + + /** + * The executor of editor tasks. + */ + @NotNull + private final JmeThreadExecutor jmeTasksExecutor; + + /** + * The executor of javaFX tasks. + */ + @NotNull + private final EditorTaskExecutor fxEditorTaskExecutor; + + private ExecutorManager() { + InitializeManager.valid(getClass()); + + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + this.jmeTasksExecutor = JmeThreadExecutor.getInstance(); + this.fxEditorTaskExecutor = new FxEditorTaskExecutor(); + + LOGGER.info("initialized."); + } + + /** + * Add a new background task. + * + * @param task the background task. + */ + @FromAnyThread + public void addBackgroundTask(@NotNull Runnable task) { + ForkJoinPool.commonPool().execute(task); + } + + /** + * Add the new task to be executed in the JavaFX thread. + * + * @param task the task. + */ + @FromAnyThread + public void addFxTask(@NotNull Runnable task) { + getFxTaskExecutor().execute(task); + } + + /** + * Add a new editor task. + * + * @param task the editor task. + */ + @FromAnyThread + public void addJmeTask(@NotNull Runnable task) { + getJmeTasksExecutor().addToExecute(task); + } + + /** + * Get the executor of javaFX tasks. + * + * @return the executor of javaFX tasks. + */ + @FromAnyThread + private @NotNull EditorTaskExecutor getFxTaskExecutor() { + return fxEditorTaskExecutor; + } + + /** + * Get the executor of jME tasks. + * + * @return the executor of jME tasks. + */ + @FromAnyThread + private @NotNull JmeThreadExecutor getJmeTasksExecutor() { + return jmeTasksExecutor; + } + + /** + * Add a scheduled task. + * + * @param runnable the scheduled task. + * @param timeout the timeout. + */ + @FromAnyThread + public void schedule(@NotNull Runnable runnable, long timeout) { + scheduledExecutorService.schedule(runnable, timeout, TimeUnit.MILLISECONDS); + } + + /** + * Add a scheduled task. + * + * @param runnable the scheduled task. + * @param delay the delay. + */ + @FromAnyThread + public void scheduleAtFixedRate(@NotNull Runnable runnable, long delay) { + scheduledExecutorService.scheduleAtFixedRate(runnable, delay, delay, TimeUnit.MILLISECONDS); + } +} diff --git a/src/main/java/com/ss/builder/manager/FileIconManager.java b/src/main/java/com/ss/builder/manager/FileIconManager.java new file mode 100644 index 00000000..7d5c2a21 --- /dev/null +++ b/src/main/java/com/ss/builder/manager/FileIconManager.java @@ -0,0 +1,398 @@ +package com.ss.builder.manager; + +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; +import static com.ss.builder.util.EditorUtils.toAssetPath; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.svg.SvgImageLoader; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.IntegerDictionary; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The class to manage file icons. + * + * @author JavaSaBr + */ +public class FileIconManager { + + private static final Logger LOGGER = LoggerManager.getLogger(FileIconManager.class); + + @FunctionalInterface + public interface IconFinder { + @Nullable String find(@NotNull Path file, @NotNull String extension); + } + + public static final String EP_ICON_FINDERS = "FileIconManager#iconFinders"; + + public static final int DEFAULT_FILE_ICON_SIZE = 16; + + private static final ExtensionPoint ICON_FINDERS = + ExtensionPointManager.register(EP_ICON_FINDERS); + + private static final ObjectDictionary EXTENSION_TO_CONTENT_TYPE = + ObjectDictionary.ofType(String.class); + + static { + + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_JPEG, "image-jpeg"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_JPG, "image-jpeg"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_TIFF, "image-tiff"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_GIF, "image-gif"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_BMP, "image-bmp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_PNG, "image-png"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_TGA, "image-x-tga"); + EXTENSION_TO_CONTENT_TYPE.put("psd", "image-x-psd"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_DDS, "image"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_HDR, "image"); + + EXTENSION_TO_CONTENT_TYPE.put("ogg", "audio-x-generic"); + EXTENSION_TO_CONTENT_TYPE.put("wav", "audio-x-generic"); + EXTENSION_TO_CONTENT_TYPE.put("mp3", "audio-x-generic"); + + EXTENSION_TO_CONTENT_TYPE.put("txt", "text"); + EXTENSION_TO_CONTENT_TYPE.put("log", "text"); + + EXTENSION_TO_CONTENT_TYPE.put("zip", "application-zip"); + EXTENSION_TO_CONTENT_TYPE.put("rar", "application-rar"); + EXTENSION_TO_CONTENT_TYPE.put("gz", "application-x-gzip"); + EXTENSION_TO_CONTENT_TYPE.put("jar", "application-x-java-archive"); + + EXTENSION_TO_CONTENT_TYPE.put("java", "application-x-java"); + + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_OBJECT, "jme3"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_SHADER_NODE, "vector"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_SCENE, "j3s"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_MATERIAL, "parquet"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_MATERIAL_DEFINITION, "text"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.MODEL_GLTF, "cube"); + + EXTENSION_TO_CONTENT_TYPE.put("obj", "x-office-drawing"); + EXTENSION_TO_CONTENT_TYPE.put("blend", "application-x-blender"); + EXTENSION_TO_CONTENT_TYPE.put("fbx", "fbx"); + EXTENSION_TO_CONTENT_TYPE.put("j3odata", "text"); + EXTENSION_TO_CONTENT_TYPE.put("xml", "text-xml"); + EXTENSION_TO_CONTENT_TYPE.put("exe", "exec"); + EXTENSION_TO_CONTENT_TYPE.put("sh", "text-x-script"); + EXTENSION_TO_CONTENT_TYPE.put("ico", "image-x-ico"); + EXTENSION_TO_CONTENT_TYPE.put("ani", "video-x-generic"); + + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_FRAGMENT, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_VERTEX, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_GEOM, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_LIB, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_TESSELLATION_CONTROL, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_TESSELLATION_EVALUATION, "text-x-csharp"); + EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.MODEL_XBUF, "image-svg+xml-compressed"); + } + + private static final Array MIME_TYPES_FOLDERS = Array.of( + Paths.get("/ui/icons/filetypes/emerald/mimetypes"), + Paths.get("/ui/icons/filetypes/") + ); + + @Nullable + private static FileIconManager instance; + + @FromAnyThread + public static @NotNull FileIconManager getInstance() { + if (instance == null) instance = new FileIconManager(); + return instance; + } + + /** + * The image cache. + */ + @NotNull + private final IntegerDictionary> imageCache; + + /** + * The cache of original images. + */ + @NotNull + private final ObjectDictionary originalImageCache; + + /** + * The cache of urs by a file extension. + */ + @NotNull + private final ObjectDictionary extensionToUrl; + + private FileIconManager() { + InitializeManager.valid(getClass()); + + this.imageCache = IntegerDictionary.ofType(ObjectDictionary.class); + this.extensionToUrl = ObjectDictionary.ofType(String.class); + this.originalImageCache = ObjectDictionary.ofType(Image.class); + + LOGGER.info("initialized."); + } + + /** + * Get an icon of the file. + * + * @param path the file. + * @param size the icon size. + * @return the icon. + */ + @FxThread + public @NotNull Image getIcon(@NotNull Path path, int size) { + return getIcon(path, Files.isDirectory(path), true, size); + } + + /** + * Get an icon of the file. + * + * @param path the file. + * @param directory the directory. + * @param tryToGetContentType true of we can try to get content type of the file. + * @param size the icon size. + * @return the icon. + */ + @FxThread + public @NotNull Image getIcon(@NotNull Path path, boolean directory, boolean tryToGetContentType, int size) { + + var extension = directory ? "folder" : FileUtils.getExtension(path); + var url = extensionToUrl.get(extension); + + if (url != null) { + return getImage(url, size); + } + + var iconFinders = ICON_FINDERS.getExtensions(); + + if (!iconFinders.isEmpty()) { + for (var iconFinder : iconFinders) { + + url = iconFinder.find(path, extension); + + var classLoader = iconFinder.getClass() + .getClassLoader(); + + if (url == null || !EditorUtils.checkExists(url, classLoader)) { + continue; + } + + extensionToUrl.put(extension, url); + + return getImage(url, classLoader, size); + } + } + + String contentType; + + if (directory) { + contentType = "folder"; + } else { + + contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); + + if (contentType == null && tryToGetContentType) { + try { + contentType = Files.probeContentType(path); + } catch (IOException e) { + LOGGER.warning(e); + } + } + } + + if (contentType != null) { + contentType = contentType.replace("/", "-"); + } + + if (contentType == null) { + LOGGER.debug("not found content type for " + path); + contentType = "none"; + } + + for (var mimeTypes : MIME_TYPES_FOLDERS) { + + Path iconPath = mimeTypes.resolve(contentType + ".svg"); + url = toAssetPath(iconPath); + + if (!EditorUtils.checkExists(url)) { + contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); + iconPath = mimeTypes.resolve(contentType + ".svg"); + url = toAssetPath(iconPath); + } + + if (!EditorUtils.checkExists(url)) { + contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); + iconPath = mimeTypes.resolve(contentType + ".png"); + url = toAssetPath(iconPath); + } + + if (EditorUtils.checkExists(url)) { + break; + } + } + + if (url == null || !EditorUtils.checkExists(url)) { + LOGGER.warning("not found image for contentType " + contentType + " and path " + path); + url = "/ui/icons/svg/document.svg"; + } + + extensionToUrl.put(extension, url); + + return getImage(url, size); + } + + /** + * Get an image by the URL. + * + * @param url the url. + * @return the image. + */ + @FxThread + public @NotNull Image getImage(@NotNull String url) { + return getImage(url, 16); + } + + /** + * Get an image by the URL. + * + * @param url the url. + * @param size the size. + * @return the image. + */ + @FxThread + public @NotNull Image getImage(@NotNull String url, int size) { + return getImage(url, size, true); + } + + /** + * Get an image by the URL. + * + * @param url the url. + * @param classLoader the class loader. + * @param size the size. + * @return the image. + */ + @FxThread + public @NotNull Image getImage(@NotNull String url, @NotNull ClassLoader classLoader, int size) { + return getImage(url, classLoader, size, true); + } + + /** + * Get an image by the URL. + * + * @param url the url. + * @param size the size. + * @param useCache true if need to use cache. + * @return the image. + */ + @FxThread + public @NotNull Image getImage(@NotNull String url, int size, boolean useCache) { + return getImage(url, getClass().getClassLoader(), size, useCache); + } + + /** + * Get an image by the URL. + * + * @param url the url. + * @param classLoader the class loader. + * @param size the size. + * @param useCache true if need to use cache. + * @return the image. + */ + @FxThread + public @NotNull Image getImage(@NotNull String url, @NotNull ClassLoader classLoader, int size, boolean useCache) { + + if (!useCache) { + return buildImage(url, classLoader, size); + } + + return imageCache.getOrCompute(size, DictionaryFactory::newObjectDictionary) + .getOrCompute(url, () -> buildImage(url, classLoader, size)); + } + + @FxThread + private @NotNull Image buildImage(@NotNull String url, @NotNull ClassLoader classLoader, int size) { + return buildImage(url, EditorUtils.getInputStream(url, classLoader), size); + } + + @FxThread + private @NotNull Image buildImage(@NotNull String url, @Nullable InputStream in, int size) { + + Image image; + + if (in != null) { + image = new Image(in, size, size, false, true); + } else { + image = new Image(url, size, size, false, true); + } + + if (!url.contains("icons/svg/")) { + originalImageCache.put(image, image); + return image; + } + + var config = EditorConfig.getInstance(); + var theme = config.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); + + if (theme.needRepaintIcons()) { + try { + + var iconColor = theme.getIconColor(); + + Image coloredImage; + + SvgImageLoader.OVERRIDE_COLOR.set(iconColor); + try { + + if (in != null) { + coloredImage = new Image(in, size, size, false, true); + } else { + coloredImage = new Image(url, size, size, false, true); + } + + } finally { + SvgImageLoader.OVERRIDE_COLOR.set(null); + } + + originalImageCache.put(coloredImage, image); + + return coloredImage; + + } catch (Throwable e) { + LOGGER.warning(e); + } + } + + originalImageCache.put(image, image); + + return image; + } + + /** + * Get an original image of the image. + * + * @param image the image. + * @return the original image. + */ + @FromAnyThread + public @NotNull Image getOriginal(@NotNull Image image) { + return notNull(originalImageCache.get(image), "not found original for " + image.getUrl()); + } +} diff --git a/src/main/java/com/ss/builder/manager/JavaFxImageManager.java b/src/main/java/com/ss/builder/manager/JavaFxImageManager.java new file mode 100644 index 00000000..358b8d6e --- /dev/null +++ b/src/main/java/com/ss/builder/manager/JavaFxImageManager.java @@ -0,0 +1,496 @@ +package com.ss.builder.manager; + +import static com.ss.rlib.common.util.FileUtils.getExtension; +import static java.awt.Image.SCALE_DEFAULT; +import static java.nio.file.StandardOpenOption.*; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.Config; +import com.ss.builder.file.reader.DdsReader; +import com.ss.builder.file.reader.TgaReader; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.ChangedCurrentAssetFolderEvent; +import com.ss.builder.fx.event.impl.DeletedFileEvent; +import com.ss.builder.fx.event.impl.FxContextCreatedEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.IntegerDictionary; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.embed.swing.SwingFXUtils; +import javafx.scene.image.Image; +import jme3tools.converters.ImageToAwt; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; + +/** + * The class to manage previews of images to JavaFX + * + * @author JavaSaBr + */ +public class JavaFxImageManager { + + private static final Logger LOGGER = LoggerManager.getLogger(JavaFxImageManager.class); + + private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); + + private static final String PREVIEW_CACHE_FOLDER = "preview-cache"; + + private static final Array FX_FORMATS = Array.of( + FileExtensions.IMAGE_PNG, + FileExtensions.IMAGE_JPG, + FileExtensions.IMAGE_JPEG, + FileExtensions.IMAGE_GIF + ); + + private static final Array JME_FORMATS = Array.of(FileExtensions.IMAGE_BMP); + + private static final Array IMAGE_IO_FORMATS = Array.of( + FileExtensions.IMAGE_HDR, + FileExtensions.IMAGE_TIFF); + + private static final Array IMAGE_FORMATS = ArrayFactory.newArray(String.class); + + /** + * The size of cached images. + */ + private static final int CACHED_IMAGES_SIZE = 30; + + static { + IMAGE_FORMATS.addAll(FX_FORMATS); + IMAGE_FORMATS.addAll(JME_FORMATS); + IMAGE_FORMATS.addAll(IMAGE_IO_FORMATS); + IMAGE_FORMATS.add(FileExtensions.IMAGE_TGA); + IMAGE_FORMATS.add(FileExtensions.IMAGE_DDS); + } + + /** + * Check the file. + * + * @param file the file + * @return true if the file is image. + */ + @FromAnyThread + public static boolean isImage(@Nullable Path file) { + return file != null && IMAGE_FORMATS.contains(getExtension(file)); + } + + /** + * Check the file by the asset path. + * + * @param assetPath the asset path + * @return true if the file is image. + */ + @FromAnyThread + public static boolean isImage(@Nullable String assetPath) { + return assetPath != null && IMAGE_FORMATS.contains(getExtension(assetPath)); + } + + @Nullable + private static JavaFxImageManager instance; + + @FromAnyThread + public static @NotNull JavaFxImageManager getInstance() { + if (instance == null) instance = new JavaFxImageManager(); + return instance; + } + + /** + * The cache of small images. + */ + @NotNull + private IntegerDictionary>> smallImageCache; + + /** + * The cache folder. + */ + @NotNull + private final Path cacheFolder; + + private JavaFxImageManager() { + InitializeManager.valid(getClass()); + + var appFolder = Config.getAppFolderInUserHome(); + + this.cacheFolder = appFolder.resolve(PREVIEW_CACHE_FOLDER); + this.smallImageCache = DictionaryFactory.newIntegerDictionary(); + + AsyncEventManager.SingleAsyncEventHandlerBuilder.of(FxContextCreatedEvent.EVENT_TYPE) + .add(() -> FX_EVENT_MANAGER.addEventHandler(DeletedFileEvent.EVENT_TYPE, this::processEvent)) + .add(() -> FX_EVENT_MANAGER.addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, this::processEvent)) + .buildAndRegister(); + + LOGGER.info("initialized."); + } + + /** + * Get the cache folder. + * + * @return the cache folder. + */ + @FromAnyThread + private @NotNull Path getCacheFolder() { + return cacheFolder; + } + + /** + * Get an image preview. + * + * @param file the image file. + * @param width the required width. + * @param height the required height. + * @return the image. + */ + @FxThread + public @NotNull Image getImagePreview(@Nullable Path file, int width, int height) { + + if (file == null || !Files.exists(file)) { + return Icons.IMAGE_512; + } + + if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { + var image = getFromCache(file.toString(), width, height); + if (image != null) { + return image; + } + } + + var url = FileUtils.getUrl(file); + var lastModFile = FileUtils.getLastModifiedTime(file); + + var image = getImagePreview(url, lastModFile, width, height); + + if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { + putImageToCache(file.toString(), image, width, height); + } + + return image; + } + + /** + * Try to get an image from the cache by path and size. + * + * @param path the path to the image. + * @param width the width. + * @param height the height. + * @return the image or null. + */ + @FxThread + private @Nullable Image getFromCache(@NotNull String path, int width, int height) { + + var heightImages = smallImageCache.get(width); + if (heightImages == null) { + return null; + } + + var images = heightImages.get(height); + if (images == null) { + return null; + } + + return images.get(path); + } + + /** + * Put the image to the cache. + * + * @param path the ath to the image. + * @param image the image. + * @param width the width. + * @param height the height. + */ + @FxThread + private void putImageToCache(@NotNull String path, @NotNull Image image, int width, int height) { + smallImageCache.get(width, DictionaryFactory::newIntegerDictionary) + .get(height, DictionaryFactory::newObjectDictionary) + .put(path, image); + } + + /** + * Get an image preview. + * + * @param resourcePath the resource path to an image. + * @param width the required width. + * @param height the required height. + * @return the image. + */ + @FxThread + public @NotNull Image getImagePreview(@Nullable String resourcePath, int width, int height) { + + if (resourcePath == null) { + throw new IllegalArgumentException("The resource path can't be null."); + } + + if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { + var image = getFromCache(resourcePath, width, height); + if (image != null) { + return image; + } + } + + var resourceManager = ResourceManager.getInstance(); + var url = resourceManager.tryToFindResource(resourcePath); + + if (url == null) { + + var realFile = EditorUtils.getRealFile(resourcePath); + if (realFile == null || !Files.exists(realFile)) { + return Icons.IMAGE_512; + } + + url = FileUtils.getUrl(realFile); + } + + var image = getImagePreview(url, null, width, height); + + if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { + putImageToCache(resourcePath, image, width, height); + } + + return image; + } + + @FxThread + private @NotNull Image getImagePreview(@NotNull URL url, @Nullable FileTime lastModFile, int width, int height) { + + var externalForm = url.toExternalForm(); + var cachedImage = getCachedImage(width, height, externalForm); + + if (Files.exists(cachedImage)) { + + var lastModCacheFile = FileUtils.getLastModifiedTime(cachedImage); + + if (lastModFile == null || lastModCacheFile.compareTo(lastModFile) >= 0) { + + var resultPath = FileUtils.getUrl(cachedImage) + .toExternalForm(); + + return new Image(resultPath, width, height, false, false); + } + } + + FileUtils.createDirectories(cachedImage.getParent()); + + var extension = getExtension(externalForm); + + if (FX_FORMATS.contains(extension)) { + return readFxImage(width, height, externalForm, cachedImage); + } else if (JME_FORMATS.contains(extension)) { + return readJmeTexture(width, height, externalForm, cachedImage); + } else if (IMAGE_IO_FORMATS.contains(extension)) { + return readIOImage(url, width, height, cachedImage); + } else if (FileExtensions.IMAGE_DDS.equals(extension)) { + + var content = Utils.get(url, first -> IOUtils.toByteArray(first.openStream())); + var pixels = DdsReader.read(content, DdsReader.ARGB, 0); + var currentWidth = DdsReader.getWidth(content); + var currentHeight = DdsReader.getHeight(content); + + var read = new BufferedImage(currentWidth, currentHeight, BufferedImage.TYPE_INT_ARGB); + read.setRGB(0, 0, currentWidth, currentHeight, pixels, 0, currentWidth); + + return scaleAndWrite(width, height, cachedImage, read, currentWidth, currentHeight); + + } else if (FileExtensions.IMAGE_TGA.equals(extension)) { + + var content = Utils.get(url, toRead -> IOUtils.toByteArray(toRead.openStream())); + + BufferedImage awtImage; + try { + awtImage = (BufferedImage) TgaReader.getImage(content); + } catch (Exception e) { + LOGGER.warning(e); + writeDefaultToCache(cachedImage); + return Icons.IMAGE_512; + } + + var imageWidth = awtImage.getWidth(); + var imageHeight = awtImage.getHeight(); + + return scaleAndWrite(width, height, cachedImage, awtImage, imageWidth, imageHeight); + } + + return Icons.IMAGE_512; + } + + /** + * Get a path to a cached image. + * + * @param width the image width. + * @param height the image height. + * @param externalForm the external form of URL. + * @return the path to a cached image. + */ + @FromAnyThread + private @NotNull Path getCachedImage(int width, int height, String externalForm) { + + var fileHash = StringUtils.toMD5(externalForm) + ".png"; + + var cacheFolder = getCacheFolder(); + var imageFolder = cacheFolder.resolve(String.valueOf(width)) + .resolve(String.valueOf(height)); + + return imageFolder.resolve(fileHash); + } + + @FxThread + private void writeDefaultToCache(@NotNull Path cacheFile) { + var bufferedImage = SwingFXUtils.fromFXImage(Icons.IMAGE_512, null); + try (var out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + ImageIO.write(bufferedImage, "png", out); + } catch (IOException ex) { + LOGGER.warning(ex); + } + } + + @FxThread + private @NotNull Image readIOImage(@NotNull URL url, int width, int height, @NotNull Path cacheFile) { + + BufferedImage read; + try { + read = ImageIO.read(url); + } catch (IOException e) { + EditorUtils.handleException(LOGGER, this, e); + return Icons.IMAGE_512; + } + + return scaleAndWrite(width, height, cacheFile, read, read.getWidth(), read.getHeight()); + } + + @FxThread + private @NotNull Image readJmeTexture( + int width, + int height, + @NotNull String externalForm, + @NotNull Path cacheFile + ) { + + var assetManager = EditorUtils.getAssetManager(); + var texture = assetManager.loadTexture(externalForm); + + BufferedImage textureImage; + try { + textureImage = ImageToAwt.convert(texture.getImage(), false, true, 0); + } catch (UnsupportedOperationException e) { + EditorUtils.handleException(LOGGER, this, e); + return Icons.IMAGE_512; + } + + int imageWidth = textureImage.getWidth(); + int imageHeight = textureImage.getHeight(); + + return scaleAndWrite(width, height, cacheFile, textureImage, imageWidth, imageHeight); + } + + @FxThread + private @NotNull Image readFxImage(int width, int height, @NotNull String externalForm, @NotNull Path cacheFile) { + + var image = new Image(externalForm); + + var imageWidth = (int) image.getWidth(); + var imageHeight = (int) image.getHeight(); + + if (imageWidth > width || imageHeight > height) { + if (imageWidth == imageHeight) { + image = new Image(externalForm, width, height, false, false); + } else if (imageWidth > imageHeight) { + float mod = imageHeight * 1F / imageWidth; + image = new Image(externalForm, width, height * mod, false, false); + } else { + float mod = imageWidth * 1F / imageHeight; + image = new Image(externalForm, width * mod, height, false, false); + } + } + + var bufferedImage = SwingFXUtils.fromFXImage(image, null); + + try (var out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + ImageIO.write(bufferedImage, "png", out); + } catch (IOException e) { + LOGGER.warning(e); + } + + return image; + } + + @FxThread + private @NotNull Image scaleAndWrite( + int targetWidth, + int targetHeight, + @NotNull Path cacheFile, + @NotNull BufferedImage textureImage, + int currentWidth, + int currentHeight + ) { + + var newImage = scaleImage(targetWidth, targetHeight, textureImage, currentWidth, currentHeight); + + try (var out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { + ImageIO.write(newImage, "png", out); + return new Image(cacheFile.toUri().toString()); + } catch (IOException e) { + LOGGER.warning(e); + return Icons.IMAGE_512; + } + } + + @FxThread + private @NotNull BufferedImage scaleImage( + int width, + int height, + @NotNull BufferedImage read, + int imageWidth, + int imageHeight + ) { + + java.awt.Image newImage = read; + + if (imageWidth > width || imageHeight > height) { + if (imageWidth == imageHeight) { + newImage = read.getScaledInstance(width, height, SCALE_DEFAULT); + } else if (imageWidth > imageHeight) { + float mod = imageHeight * 1F / imageWidth; + newImage = read.getScaledInstance(width, (int) (height * mod), SCALE_DEFAULT); + } else if (imageHeight > imageWidth) { + float mod = imageWidth * 1F / imageHeight; + newImage = read.getScaledInstance((int) (width * mod), height, SCALE_DEFAULT); + } + } + + var bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + var g2d = bufferedImage.createGraphics(); + g2d.drawImage(newImage, 0, 0, null); + g2d.dispose(); + + return bufferedImage; + } + + @FxThread + private void processEvent(@NotNull DeletedFileEvent event) { + //TODO need to add remove from cache + } + + @FxThread + private void processEvent(@NotNull ChangedCurrentAssetFolderEvent event) { + smallImageCache.clear(); + } +} diff --git a/src/main/java/com/ss/editor/manager/JmeFilePreviewManager.java b/src/main/java/com/ss/builder/manager/JmeFilePreviewManager.java similarity index 90% rename from src/main/java/com/ss/editor/manager/JmeFilePreviewManager.java rename to src/main/java/com/ss/builder/manager/JmeFilePreviewManager.java index 058d9076..c73ee73a 100644 --- a/src/main/java/com/ss/editor/manager/JmeFilePreviewManager.java +++ b/src/main/java/com/ss/builder/manager/JmeFilePreviewManager.java @@ -1,11 +1,11 @@ -package com.ss.editor.manager; +package com.ss.builder.manager; import static com.jme3.jfx.injfx.JmeToJfxIntegrator.bind; import static com.jme3.jfx.injfx.processor.FrameTransferSceneProcessor.TransferMode.ON_CHANGES; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; +import static com.ss.builder.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION; +import static com.ss.builder.config.DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION; +import static com.ss.builder.util.EditorUtils.getAssetFile; +import static com.ss.builder.util.EditorUtils.toAssetPath; import static com.ss.rlib.common.util.FileUtils.getExtension; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.asset.AssetNotFoundException; @@ -24,17 +24,17 @@ import com.jme3.scene.control.AbstractControl; import com.jme3.scene.shape.Box; import com.jme3.util.SkyFactory; -import com.ss.editor.FileExtensions; -import com.ss.editor.JmeApplication; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.asset.locator.FolderAssetLocator; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.executor.impl.JmeThreadExecutor; -import com.ss.editor.model.EditorCamera; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.TangentGenerator; +import com.ss.builder.FileExtensions; +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.executor.impl.JmeThreadExecutor; +import com.ss.builder.jme.asset.locator.FolderAssetLocator; +import com.ss.builder.model.EditorCamera; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.TangentGenerator; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.util.StringUtils; @@ -212,7 +212,7 @@ private JmeFilePreviewManager() { var executorManager = ExecutorManager.getInstance(); executorManager.addFxTask(() -> { - var scene = EditorUtil.getFxScene(); + var scene = EditorUtils.getFxScene(); var container = scene.getHideLayer(); FxUtils.addChild(container, imageView); @@ -237,7 +237,7 @@ protected void controlUpdate(float tpf) { @JmeThread private void notifyProbeComplete() { - var rootNode = EditorUtil.getPreviewNode(); + var rootNode = EditorUtils.getPreviewNode(); rootNode.attachChild(modelNode); } @@ -321,7 +321,7 @@ public void show(@NotNull String assetPath, int fitWidth, int fitHeight) { private void showObject(@NotNull String path, boolean external) { prepareProcessor(); - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); Spatial model; @@ -340,7 +340,7 @@ private void showObject(@NotNull String path, boolean external) { tryToLoad(model); - var rootNode = EditorUtil.getPreviewNode(); + var rootNode = EditorUtils.getPreviewNode(); rootNode.detachChild(modelNode); } @@ -353,13 +353,13 @@ private void showObject(@NotNull String path, boolean external) { private void tryToLoad(@NotNull Spatial model) { try { - var renderManager = EditorUtil.getRenderManager(); + var renderManager = EditorUtils.getRenderManager(); renderManager.preloadScene(model); modelNode.attachChild(model); } catch (RendererException | AssetNotFoundException | UnsupportedOperationException e) { - EditorUtil.handleException(LOGGER, this, e); + EditorUtils.handleException(LOGGER, this, e); } } @@ -375,7 +375,7 @@ private void prepareProcessor() { frame = 0; - var camera = EditorUtil.getPreviewCamera(); + var camera = EditorUtils.getPreviewCamera(); camera.setLocation(CAMERA_LOCATION); camera.setRotation(CAMERA_ROTATION); @@ -391,13 +391,13 @@ private void prepareProcessor() { private void showMaterial(@NotNull String path) { prepareProcessor(); - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); var material = assetManager.loadMaterial(path); testBox.setMaterial(material); tryToLoad(testBox); - var rootNode = EditorUtil.getPreviewNode(); + var rootNode = EditorUtils.getPreviewNode(); rootNode.detachChild(modelNode); } @@ -459,8 +459,6 @@ private void clearImpl() { var editorCamera = new EditorCamera(camera, cameraNode); editorCamera.setMaxDistance(10000); editorCamera.setMinDistance(0.01F); - editorCamera.setSmoothMotion(false); - editorCamera.setRotationSensitivity(1); editorCamera.setZoomSensitivity(0.2F); //TODO added supporting moving the camera diff --git a/src/main/java/com/ss/builder/manager/PluginManager.java b/src/main/java/com/ss/builder/manager/PluginManager.java new file mode 100644 index 00000000..725ab007 --- /dev/null +++ b/src/main/java/com/ss/builder/manager/PluginManager.java @@ -0,0 +1,301 @@ +package com.ss.builder.manager; + +import com.ss.builder.JmeApplication; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.Config; +import com.ss.builder.fx.css.CssRegistry; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.plugin.EditorPlugin; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.plugin.ConfigurablePluginSystem; +import com.ss.rlib.common.plugin.exception.PreloadPluginException; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.plugin.impl.PluginSystemFactory; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.ObjectUtils; +import com.ss.rlib.common.util.Utils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +/** + * The manager to work with plugins. + * + * @author JavaSaBr + */ +public class PluginManager { + + private static final Logger LOGGER = LoggerManager.getLogger(PluginManager.class); + + @Nullable + private static PluginManager instance; + + public static @NotNull PluginManager getInstance() { + + if (instance == null) { + instance = new PluginManager(); + } + + return instance; + } + + @NotNull + private final CountDownLatch waiter; + + /** + * The plugin system. + */ + @Nullable + private volatile ConfigurablePluginSystem pluginSystem; + + private PluginManager() { + InitializeManager.valid(getClass()); + + this.waiter = new CountDownLatch(1); + + ExecutorManager.getInstance() + .addBackgroundTask(this::loadPluginsInBackground); + + AsyncEventManager.SingleAsyncEventHandlerBuilder.of(EditorFinishedLoadingEvent.EVENT_TYPE) + .add(this::onFinishLoading) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::onAfterCreateJmeContext) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .add(PluginsLoadedEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.SingleAsyncEventHandlerBuilder.of(FxContextCreatedEvent.EVENT_TYPE) + .add(this::onAfterCreateJavaFxContext) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::registeredExtensions) + .add(FxSceneCreatedEvent.EVENT_TYPE) + .add(PluginsRegisteredResourcesEvent.EVENT_TYPE) + .buildAndRegister(); + } + + /** + * Get the plugin system. + * + * @return the plugin system. + */ + @FromAnyThread + private @NotNull ConfigurablePluginSystem getPluginSystem() { + return ObjectUtils.notNull(pluginSystem); + } + + @BackgroundThread + private void loadPluginsInBackground() { + + var pluginSystem = PluginSystemFactory.newBasePluginSystem(); + pluginSystem.setAppVersion(Config.APP_VERSION); + + var folderInUserHome = Config.getAppFolderInUserHome(); + var embeddedPath = System.getProperty("editor.embedded.plugins.path"); + + if (embeddedPath != null && Files.exists(Paths.get(embeddedPath))) { + + var embeddedPluginPath = Paths.get(embeddedPath); + + LOGGER.debug(this, "embedded plugin path: " + embeddedPluginPath); + + pluginSystem.configureEmbeddedPluginPath(embeddedPluginPath); + + } else { + + var rootFolder = Utils.getRootFolderFromClass(JmeApplication.class); + var embeddedPluginPath = rootFolder.resolve("embedded-plugins"); + + LOGGER.debug(this, "embedded plugin path: " + embeddedPluginPath); + + if (Files.exists(embeddedPluginPath)) { + pluginSystem.configureEmbeddedPluginPath(embeddedPluginPath); + } else { + LOGGER.warning(this, "The embedded plugin folder doesn't exists."); + } + } + + var userPluginsFolder = folderInUserHome.resolve("plugins"); + + LOGGER.debug(this, "installation plugin path: " + userPluginsFolder); + + if (!Files.exists(userPluginsFolder)) { + FileUtils.createDirectories(userPluginsFolder); + } + + pluginSystem.configureInstallationPluginsPath(userPluginsFolder); + pluginSystem.preLoad() + .exceptionally(this::handleException) + .thenApply(ConfigurablePluginSystem::initialize) + .join(); + + this.pluginSystem = pluginSystem; + + waiter.countDown(); + + var eventManager = AsyncEventManager.getInstance(); + eventManager.notify(new PluginsLoadedEvent()); + + handlePlugins(editorPlugin -> + editorPlugin.register(ResourceManager.getInstance())); + + eventManager.notify(new PluginsRegisteredResourcesEvent()); + + } + + @BackgroundThread + private @Nullable ConfigurablePluginSystem handleException(@Nullable Throwable throwable) { + + if (throwable instanceof PreloadPluginException) { + FileUtils.delete(((PreloadPluginException) throwable).getPath()); + } + + throw new RuntimeException(throwable); + } + + /** + * Register all extension of all plugins. + */ + @BackgroundThread + private void registeredExtensions() { + + var executorManager = ExecutorManager.getInstance(); + executorManager.addBackgroundTask(() -> { + + handlePlugins(editorPlugin -> + editorPlugin.register(CssRegistry.getInstance())); + + AsyncEventManager.getInstance() + .notify(new PluginCssLoadedEvent()); + }); + + executorManager.addBackgroundTask(() -> { + + handlePlugins(editorPlugin -> + editorPlugin.register(ExtensionPointManager.getInstance())); + + AsyncEventManager.getInstance() + .notify(new AllPluginsExtensionsRegisteredEvent()); + }); + } + + /** + * Install a new plugin to the system. + * + * @param path the path to the plugin. + */ + public void installPlugin(@NotNull Path path) { + getPluginSystem().installPlugin(path, false); + } + + /** + * Remove a plugin from this editor. + * + * @param plugin the plugin. + */ + public void removePlugin(@NotNull EditorPlugin plugin) { + getPluginSystem().removePlugin(plugin); + } + + /** + * Do some things after when JME context was created. + */ + @BackgroundThread + private void onAfterCreateJmeContext() { + handlePlugins(editorPlugin -> { + + editorPlugin.onAfterCreateJmeContext(getPluginSystem()); + + var classLoader = editorPlugin.getContainer(). + getClassLoader(); + + ExecutorManager.getInstance() + .addFxTask(() -> EditorUtils.getAssetManager() + .addClassLoader(classLoader)); + }); + } + + /** + * Do some things after when JavaFX context was created. + */ + @BackgroundThread + private void onAfterCreateJavaFxContext() { + handlePlugins(editorPlugin -> + editorPlugin.onAfterCreateJavaFxContext(getPluginSystem())); + } + + /** + * Do some things before when the editor is ready to work. + */ + @BackgroundThread + private void onFinishLoading() { + + Utils.run(waiter, CountDownLatch::await); + + handlePlugins(editorPlugin -> + editorPlugin.onFinishLoading(getPluginSystem())); + } + + /** + * Handle each loaded plugin now. + * + * @param consumer the consumer. + */ + @FromAnyThread + public void handlePluginsNow(@NotNull Consumer consumer) { + handlePlugins(consumer); + } + + /** + * Handle each loaded plugin in background. + * + * @param consumer the consumer. + */ + @FromAnyThread + public void handlePluginsInBackground(@NotNull Consumer consumer) { + ExecutorManager.getInstance() + .addBackgroundTask(() -> handlePlugins(consumer)); + } + + /** + * Handle each loaded plugin in background and execute the result task in result. + * + * @param consumer the consumer. + * @param result the result task. + */ + @FromAnyThread + public void handlePluginsInBackground(@NotNull Consumer consumer, @NotNull Runnable result) { + ExecutorManager.getInstance() + .addBackgroundTask(() -> { + handlePlugins(consumer); + result.run(); + }); + } + + @FromAnyThread + private void handlePlugins(@NotNull Consumer consumer) { + getPluginSystem().getPlugins().stream() + .filter(EditorPlugin.class::isInstance) + .map(EditorPlugin.class::cast) + .forEach(editorPlugin -> safeApply(consumer, editorPlugin)); + } + + @FromAnyThread + private void safeApply(@NotNull Consumer consumer, @NotNull EditorPlugin editorPlugin) { + try { + consumer.accept(editorPlugin); + } catch (Throwable e) { + LOGGER.warning(e); + } + } +} diff --git a/src/main/java/com/ss/builder/manager/RemoteControlManager.java b/src/main/java/com/ss/builder/manager/RemoteControlManager.java new file mode 100644 index 00000000..a3b8bebd --- /dev/null +++ b/src/main/java/com/ss/builder/manager/RemoteControlManager.java @@ -0,0 +1,148 @@ +package com.ss.builder.manager; + +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.Config; +import com.ss.builder.fx.event.impl.CoreClassesScannedEvent; +import com.ss.builder.fx.event.impl.FxContextCreatedEvent; +import com.ss.builder.fx.event.impl.JmeContextCreatedEvent; +import com.ss.builder.manager.ClasspathManager.Scope; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.network.NetworkConfig; +import com.ss.rlib.common.network.NetworkFactory; +import com.ss.rlib.common.network.packet.ReadablePacket; +import com.ss.rlib.common.network.packet.ReadablePacketRegistry; +import com.ss.rlib.common.network.server.AcceptHandler; +import com.ss.rlib.common.network.server.ServerNetwork; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.net.InetSocketAddress; + +/** + * The manager to process remote control. + * + * @author JavaSaBr + */ +public class RemoteControlManager { + + private static final NetworkConfig NETWORK_CONFIG = new NetworkConfig() { + + @Override + public int getReadBufferSize() { + return Short.MAX_VALUE * 2; + } + + @Override + public int getWriteBufferSize() { + return Short.MAX_VALUE * 2; + } + }; + + @Nullable + private static RemoteControlManager instance; + + public static @NotNull RemoteControlManager getInstance() { + if (instance == null) instance = new RemoteControlManager(); + return instance; + } + + /** + * The packet registry. + */ + @Nullable + private volatile ReadablePacketRegistry packetRegistry; + + /** + * The control server. + */ + @Nullable + private volatile ServerNetwork serverNetwork; + + /** + * True if jME context is already created. + */ + private volatile boolean canStart; + + private RemoteControlManager() { + InitializeManager.valid(getClass()); + + if (Config.REMOTE_CONTROL_PORT == -1) { + return; + } + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::createPacketRegistry) + .add(CoreClassesScannedEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::start) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .add(FxContextCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + } + + /** + * Get a packet registry. + * + * @return the packet registry. + */ + @FromAnyThread + private @Nullable ReadablePacketRegistry getPacketRegistry() { + return packetRegistry; + } + + /** + * Create a packet registry when the {@link ClasspathManager} will be initialized. + */ + @BackgroundThread + private synchronized void createPacketRegistry() { + + var classpathManager = ClasspathManager.getInstance(); + + Class[] packets = unsafeCast(classpathManager + .findImplements(ReadablePacket.class, Scope.ONLY_CORE) + .toArray(Class.class)); + + this.packetRegistry = ReadablePacketRegistry.of(packets); + + if (canStart) { + start(); + } + } + + /** + * Start the remote control in background. + */ + @BackgroundThread + private void startInBackground() { + + var serverNetwork = NetworkFactory.newDefaultAsyncServerNetwork(NETWORK_CONFIG, + packetRegistry, AcceptHandler.newDefault()); + + try { + serverNetwork.bind(new InetSocketAddress(Config.REMOTE_CONTROL_PORT)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + this.serverNetwork = serverNetwork; + } + + /** + * Start the remote control if need. + */ + @FromAnyThread + private synchronized void start() { + canStart = true; + + var packetRegistry = getPacketRegistry(); + if (packetRegistry == null) { + return; + } + + ExecutorManager.getInstance() + .addBackgroundTask(this::startInBackground); + } +} diff --git a/src/main/java/com/ss/builder/manager/ResourceManager.java b/src/main/java/com/ss/builder/manager/ResourceManager.java new file mode 100644 index 00000000..5e938690 --- /dev/null +++ b/src/main/java/com/ss/builder/manager/ResourceManager.java @@ -0,0 +1,783 @@ +package com.ss.builder.manager; + +import static com.ss.rlib.common.util.ArrayUtils.contains; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static com.ss.rlib.common.util.array.ArrayFactory.toArray; +import static java.lang.System.currentTimeMillis; +import static java.nio.file.StandardWatchEventKinds.*; +import com.jme3.asset.AssetEventListener; +import com.jme3.asset.AssetKey; +import com.ss.builder.EditorThread; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.*; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.util.SimpleFileVisitor; +import com.ss.builder.util.SimpleFolderVisitor; +import com.ss.rlib.common.concurrent.util.ThreadUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.Utils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayComparator; +import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.array.ConcurrentArray; +import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; +import com.ss.rlib.common.util.dictionary.Dictionary; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import com.ss.rlib.common.util.ref.Reference; +import com.ss.rlib.common.util.ref.ReferenceFactory; +import com.ss.rlib.common.util.ref.ReferenceType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.*; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * The class to manage working with resources of an editor. + * + * @author JavaSaBr + */ +public class ResourceManager extends EditorThread implements AssetEventListener { + + private static final Logger LOGGER = LoggerManager.getLogger(ResourceManager.class); + + private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); + private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); + + private static final ArrayComparator STRING_ARRAY_COMPARATOR = StringUtils::compareIgnoreCase; + + private static final WatchService WATCH_SERVICE = FileUtils.newDefaultWatchService(); + + @Nullable + private static ResourceManager instance; + + @FromAnyThread + public static @NotNull ResourceManager getInstance() { + if (instance == null) instance = new ResourceManager(); + return instance; + } + + /** + * The table with last modify dates. + */ + @NotNull + private final ConcurrentObjectDictionary assetCacheTable; + + /** + * The table with interested resources. + */ + @NotNull + private final ConcurrentObjectDictionary> interestedResources; + + /** + * The table with interested resources in the classpath. + */ + @NotNull + private final ConcurrentObjectDictionary> interestedResourcesInClasspath; + + /** + * The list of additional ENVs. + */ + @NotNull + private final ConcurrentArray additionalEnvs; + + /** + * The list of an additional classpath. + */ + @NotNull + private final ConcurrentArray classLoaders; + + /** + * The list of resources in the classpath. + */ + @NotNull + private final ConcurrentArray resourcesInClasspath; + + /** + * The list of keys for watching to folders. + */ + @NotNull + private final ConcurrentArray watchKeys; + + private ResourceManager() { + InitializeManager.valid(getClass()); + + this.assetCacheTable = ConcurrentObjectDictionary.ofType(String.class, Reference.class); + this.additionalEnvs = ConcurrentArray.ofType(Path.class); + this.watchKeys = ConcurrentArray.ofType(WatchKey.class); + this.classLoaders = ConcurrentArray.ofType(URLClassLoader.class); + this.resourcesInClasspath = ConcurrentArray.ofType(String.class); + this.interestedResources = ConcurrentObjectDictionary.ofType(String.class, ConcurrentArray.class); + this.interestedResourcesInClasspath = ConcurrentObjectDictionary.ofType(String.class, ConcurrentArray.class); + + registerInterestedFileType(FileExtensions.JME_MATERIAL_DEFINITION); + updateAdditionalEnvs(); + start(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::registerFxListeners) + .add(EditorFinishedLoadingEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::registerAssetListenerAndReload) + .add(ManagersInitializedEvent.EVENT_TYPE) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::prepareClasspathResources) + .add(CoreClassesScannedEvent.EVENT_TYPE) + .add(PluginsRegisteredResourcesEvent.EVENT_TYPE) + .buildAndRegister(); + + LOGGER.info("initialized."); + } + + /** + * Register all FX listeners. + */ + @BackgroundThread + private void registerFxListeners() { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + FX_EVENT_MANAGER.addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, this::processChangeAsset); + FX_EVENT_MANAGER.addEventHandler(RequestedRefreshAssetEvent.EVENT_TYPE, this::processRefreshAsset); + FX_EVENT_MANAGER.addEventHandler(CreatedFileEvent.EVENT_TYPE, this::processEvent); + FX_EVENT_MANAGER.addEventHandler(DeletedFileEvent.EVENT_TYPE, this::processEvent); + LOGGER.info("registered FX listeners."); + }); + } + + /** + * Register an asset listener and reload this manager. + */ + @BackgroundThread + private void registerAssetListenerAndReload() { + var executorManager = ExecutorManager.getInstance(); + executorManager.addJmeTask(() -> { + var assetManager = EditorUtils.getAssetManager(); + assetManager.addAssetEventListener(this); + reload(); + LOGGER.info("registered an asset listener and reloaded."); + }); + } + + /** + * Try to find a resource by the resource path. + * + * @param resourcePath the resource path. + * @return the URL or null. + */ + @FromAnyThread + public @Nullable URL tryToFindResource(@NotNull String resourcePath) { + + var classLoaders = ArrayFactory.newArray(ClassLoader.class); + classLoaders.add(getClass().getClassLoader()); + + var classpathManager = ClasspathManager.getInstance(); + var classesLoader = classpathManager.getClassesLoader(); + var librariesLoader = classpathManager.getLibrariesLoader(); + + if (classesLoader != null) { + classLoaders.add(classesLoader); + } + + if (librariesLoader != null) { + classLoaders.add(librariesLoader); + } + + var pluginManager = PluginManager.getInstance(); + pluginManager.handlePluginsNow(plugin -> classLoaders.add(plugin.getClassLoader())); + + var altResourcePath = "/" + resourcePath; + + URL url = null; + + for (var classLoader : classLoaders) { + url = classLoader.getResource(resourcePath); + if (url != null) break; + url = classLoader.getResource(altResourcePath); + if (url != null) break; + } + + if (url == null) { + url = getClass().getResource("/" + resourcePath); + } + + return url; + } + + /** + * Get the table with interested resources. + * + * @return the table with interested resources. + */ + @FromAnyThread + private @NotNull ConcurrentObjectDictionary> getInterestedResources() { + return interestedResources; + } + + /** + * Get the table with interested resources in the classpath. + * + * @return the table with interested resources in the classpath. + */ + @FromAnyThread + private @NotNull ConcurrentObjectDictionary> getInterestedResourcesInClasspath() { + return interestedResourcesInClasspath; + } + + /** + * Register the file type of interested resources. + * + * @param fileExtension the file type. + */ + @FromAnyThread + public void registerInterestedFileType(@NotNull String fileExtension) { + + getInterestedResources().runInWriteLock(fileExtension, (dictionary, extension) -> { + if (!dictionary.containsKey(extension)) { + dictionary.put(extension, ArrayFactory.newConcurrentStampedLockArray(String.class)); + } + }); + + getInterestedResourcesInClasspath().runInWriteLock(fileExtension, (dictionary, extension) -> { + if (!dictionary.containsKey(extension)) { + dictionary.put(extension, ArrayFactory.newConcurrentStampedLockArray(String.class)); + } + }); + } + + @Override + @JmeThread + public void assetLoaded(@NotNull AssetKey key) { + + if (key.getCacheType() == null) { + return; + } + + var extension = key.getExtension(); + if (StringUtils.isEmpty(extension)) { + return; + } + + var reference = getAssetCacheTable() + .getInReadLock(key.getName(), (references, name) -> + references.get(name, () -> ReferenceFactory.newRef(ReferenceType.LONG))); + + reference.setLong(currentTimeMillis()); + } + + @Override + @JmeThread + public void assetRequested(@NotNull AssetKey key) { + + if (key.getCacheType() == null) { + return; + } + + var extension = key.getExtension(); + if (StringUtils.isEmpty(extension)){ + return; + } + + var reference = getAssetCacheTable() + .getInReadLock(key.getName(), ObjectDictionary::get); + + if (reference == null) { + return; + } + + var realFile = EditorUtils.getRealFile(Paths.get(key.getName())); + if (realFile == null || !Files.exists(realFile)) { + return; + } + + var timestamp = reference.getLong(); + + var lastModifiedTime = FileUtils.getLastModifiedTime(realFile); + if (lastModifiedTime.to(TimeUnit.MILLISECONDS) <= timestamp) { + return; + } + + EditorUtils.getAssetManager() + .deleteFromCache(key); + } + + @Override + @FromAnyThread + public void assetDependencyNotFound(@NotNull AssetKey parentKey, @NotNull AssetKey dependentAssetKey) { + } + + /** + * Update the list with additional ENVs. + */ + @FromAnyThread + public void updateAdditionalEnvs() { + EXECUTOR_MANAGER.addBackgroundTask(this::updateAdditionalEnvsInBackground); + } + + /** + * Update the list of additional ENVs textures. + */ + @BackgroundThread + private void updateAdditionalEnvsInBackground() { + + var editorConfig = EditorConfig.getInstance(); + var additionalEnvs = getAdditionalEnvs(); + additionalEnvs.runInWriteLock(Collection::clear); + + var folder = editorConfig.getFile(DefaultSettingsProvider.Preferences.PREF_FAST_SKY_FOLDER); + if (folder == null) { + return; + } + + additionalEnvs.runInWriteLock(paths -> + paths.addAll(FileUtils.getFiles(folder, FileExtensions.IMAGE_HDR, FileExtensions.IMAGE_TGA, FileExtensions.IMAGE_PNG))); + } + + /** + * Get a list with additional ENVs. + * + * @return the list. + */ + @FromAnyThread + public @NotNull ConcurrentArray getAdditionalEnvs() { + return additionalEnvs; + } + + /** + * Get the table with last modify dates. + * + * @return the table with last modify dates. + */ + @FromAnyThread + private @NotNull ConcurrentObjectDictionary getAssetCacheTable() { + return assetCacheTable; + } + + /** + * Handle a removed file. + */ + @FxThread + private void processEvent(@NotNull DeletedFileEvent event) { + + if (event.isDirectory()) { + return; + } + + var file = event.getFile(); + var extension = FileUtils.getExtension(file); + + var resources = getInterestedResources() + .getInReadLock(extension, ObjectDictionary::get); + + var assetFile = notNull(EditorUtils.getAssetFile(file)); + var assetPath = EditorUtils.toAssetPath(assetFile); + + if (resources != null) { + resources.runInWriteLock(assetPath, Array::fastRemove); + } + + if (extension.endsWith(FileExtensions.JAVA_LIBRARY)) { + + var assetManager = EditorUtils.getAssetManager(); + var url = FileUtils.getUrl(file); + + var classLoaders = getClassLoaders(); + classLoaders.runInWriteLock(urlClassLoaders -> { + + var oldLoader = urlClassLoaders.findAny(url, + (loader, toCheck) -> contains(loader.getURLs(), toCheck)); + + if (oldLoader != null) { + urlClassLoaders.fastRemove(oldLoader); + EXECUTOR_MANAGER.addJmeTask(() -> + assetManager.removeClassLoader(oldLoader)); + } + }); + } + } + + /** + * Handle a created file. + */ + @FxThread + private void processEvent(@NotNull CreatedFileEvent event) { + if (!event.isDirectory()) { + handleFile(event.getFile()); + } + } + + /** + * Get the list of resources in the classpath. + * + * @return the list of resources in the classpath. + */ + @FromAnyThread + private @NotNull ConcurrentArray getResourcesInClasspath() { + return resourcesInClasspath; + } + + /** + * Prepare classpath resources. + */ + @BackgroundThread + private void prepareClasspathResources() { + + var classpathManager = ClasspathManager.getInstance(); + + var resourcesInClasspath = getResourcesInClasspath(); + resourcesInClasspath.runInWriteLock(array -> + array.addAll(classpathManager.getAllResources())); + + getInterestedResourcesInClasspath().runInWriteLock(dictionary -> { + resourcesInClasspath.runInReadLock(array -> { + for (var resource : array) { + var resources = dictionary.get(FileUtils.getExtension(resource)); + if (resources != null) { + resources.runInWriteLock(resource, Collection::add); + } + } + }); + }); + + LOGGER.info("prepared classpath resources."); + } + + /** + * Get the list of class loaders. + * + * @return the list of class loaders. + */ + @FromAnyThread + public @NotNull ConcurrentArray getClassLoaders() { + return classLoaders; + } + + /** + * Get available resources by the file extension. + * + * @param extension the interested extension. + * @return the list of all available material definitions. + */ + @FromAnyThread + public @NotNull Array getAvailableResources(@NotNull String extension) { + var result = ArrayFactory.newArraySet(String.class); + addAvailableResources(result, extension); + return result; + } + + /** + * Add available interested resources to the result array by the file extension. + * + * @param result the array to store result. + * @param extension the interested extension. + */ + @FromAnyThread + public void addAvailableResources(@NotNull Array result, @NotNull String extension) { + + var resourcesInClasspath = getInterestedResourcesInClasspath(); + var resources = getInterestedResources(); + + var inAsset = resources.getInReadLock(extension, ObjectDictionary::get); + var inClassPath = resourcesInClasspath.getInReadLock(extension, ObjectDictionary::get); + + if (inAsset != null) { + inAsset.runInReadLock(result, + (res, toStore) -> toStore.addAll(res)); + } + + if (inClassPath != null) { + inClassPath.runInReadLock(result, + (res, toStore) -> toStore.addAll(res)); + } + + result.sort(STRING_ARRAY_COMPARATOR); + } + + /** + * Reload available resources. + */ + @BackgroundThread + private void reloadInBackground() { + + var lastModifyTable = getAssetCacheTable(); + lastModifyTable.runInWriteLock(Dictionary::clear); + + var watchKeys = getWatchKeys(); + watchKeys.runInWriteLock(keys -> { + keys.forEach(WatchKey::cancel); + keys.clear(); + }); + + var classLoadersCopy = ArrayFactory.newArray(ClassLoader.class); + var classLoaders = getClassLoaders(); + classLoaders.runInWriteLock(classLoadersCopy, (urlClassLoaders, toStore) -> { + toStore.addAll(urlClassLoaders); + urlClassLoaders.clear(); + }); + + EXECUTOR_MANAGER.addJmeTask(() -> { + var assetManager = EditorUtils.getAssetManager(); + classLoadersCopy.forEach(assetManager::removeClassLoader); + assetManager.clearCache(); + }); + + var interestedResources = getInterestedResources(); + interestedResources.runInWriteLock(resources -> resources.forEach(Collection::clear)); + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + if (currentAsset == null) { + return; + } + + FileUtils.walkFileTree(currentAsset, (SimpleFileVisitor) + (file, attrs) -> handleFile(file)); + + watchKeys.add(Utils.get(currentAsset, toRegister -> + toRegister.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY))); + + FileUtils.walkFileTree(currentAsset, (SimpleFolderVisitor) + (file, attrs) -> registerFiles(watchKeys, file)); + } + + /** + * Reload available resources. + */ + @FromAnyThread + public void reload() { + EXECUTOR_MANAGER.addBackgroundTask(this::reloadInBackground); + } + + @FromAnyThread + private static void registerFiles(@NotNull Array watchKeys, @NotNull Path file) { + watchKeys.add(Utils.get(file, toRegister -> + toRegister.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY))); + } + + /** + * Handle a file event in an asset folder. + */ + @FromAnyThread + private void handleFile(@NotNull Path file) { + + if (Files.isDirectory(file)) { + return; + } + + var extension = FileUtils.getExtension(file); + var toStore = getInterestedResources() + .getInReadLock(extension, ObjectDictionary::get); + + if (toStore != null) { + var assetFile = notNull(EditorUtils.getAssetFile(file)); + var assetPath = EditorUtils.toAssetPath(assetFile); + toStore.runInWriteLock(assetPath, Collection::add); + } + + if (extension.endsWith(FileExtensions.JAVA_LIBRARY)) { + + var assetManager = EditorUtils.getAssetManager(); + var url = Utils.get(file, FileUtils::getUrl); + + var classLoaders = getClassLoaders(); + long stamp = classLoaders.writeLock(); + try { + + var oldLoader = classLoaders.findAny(url, + (loader, toCheck) -> contains(loader.getURLs(), toCheck)); + + if (oldLoader != null) { + return; + } + + var newLoader = new URLClassLoader(toArray(url), getClass().getClassLoader()); + classLoaders.add(newLoader); + + EXECUTOR_MANAGER.addJmeTask(() -> + assetManager.addClassLoader(newLoader)); + + } finally { + classLoaders.writeUnlock(stamp); + } + } + } + + @Override + public void run() { + super.run(); + + while (true) { + + ThreadUtils.sleep(200); + + var watchKeys = getWatchKeys(); + + List> watchEvents = null; + WatchKey watchKey = null; + + long stamp = watchKeys.readLock(); + try { + + for (var key : watchKeys) { + + watchKey = key; + watchEvents = key.pollEvents(); + + if (!watchEvents.isEmpty()) { + break; + } + } + + } finally { + watchKeys.readUnlock(stamp); + } + + if (watchEvents == null || watchEvents.isEmpty()) { + continue; + } + + for (var watchEvent : watchEvents) { + + var file = (Path) watchEvent.context(); + var folder = (Path) watchKey.watchable(); + var realFile = folder.resolve(file); + + if (watchEvent.kind() == ENTRY_CREATE) { + + var directory = Files.isDirectory(realFile); + + var event = new CreatedFileEvent(); + event.setFile(realFile); + event.setNeedSelect(false); + event.setDirectory(directory); + + if (directory) { + registerWatchKey(realFile); + } + + FX_EVENT_MANAGER.notify(event); + + } else if (watchEvent.kind() == ENTRY_DELETE) { + + var directory = Files.isDirectory(realFile); + + var event = new DeletedFileEvent(); + event.setFile(realFile); + event.setDirectory(directory); + + removeWatchKeyFor(realFile); + + FX_EVENT_MANAGER.notify(event); + + } else if (watchEvent.kind() == ENTRY_MODIFY) { + + var event = new FileChangedEvent(); + event.setFile(realFile); + + FX_EVENT_MANAGER.notify(event); + } + } + } + } + + /** + * Find a watch key for the file. + * + * @param path the file. + * @return the watch key or null. + */ + @FromAnyThread + private @Nullable WatchKey findWatchKey(@NotNull Path path) { + + var watchKeys = getWatchKeys(); + var stamp = watchKeys.readLock(); + try { + + return watchKeys.findAny(path, + (watchKey, toCheck) -> watchKey.watchable().equals(toCheck)); + + } finally { + watchKeys.readUnlock(stamp); + } + } + + /** + * Remove a watch key for the file. + * + * @param path the file. + */ + @FromAnyThread + private void removeWatchKeyFor(@NotNull Path path) { + + var watchKey = findWatchKey(path); + if (watchKey == null) { + return; + } + + getWatchKeys().runInWriteLock(watchKey, Array::fastRemove); + + watchKey.cancel(); + } + + /** + * Register a watch key for the file. + * + * @param path the file. + */ + @FromAnyThread + private void registerWatchKey(@NotNull Path path) { + + var watchKeys = getWatchKeys(); + var stamp = watchKeys.writeLock(); + try { + + watchKeys.add(Utils.get(path, f -> + f.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY))); + + } finally { + watchKeys.writeUnlock(stamp); + } + } + + /** + * Handle refreshing asset folder. + */ + @FromAnyThread + private void processRefreshAsset(@NotNull RequestedRefreshAssetEvent event) { + EXECUTOR_MANAGER.addBackgroundTask(this::reload); + } + + /** + * Handle changing asset folder. + */ + @FromAnyThread + private void processChangeAsset(@NotNull ChangedCurrentAssetFolderEvent event) { + EXECUTOR_MANAGER.addBackgroundTask(this::reload); + } + + /** + * Get the list of keys for watching to folders. + * + * @return the list of keys for watching to folders. + */ + @FromAnyThread + private @NotNull ConcurrentArray getWatchKeys() { + return watchKeys; + } +} diff --git a/src/main/java/com/ss/builder/manager/WorkspaceManager.java b/src/main/java/com/ss/builder/manager/WorkspaceManager.java new file mode 100644 index 00000000..ac8ef13e --- /dev/null +++ b/src/main/java/com/ss/builder/manager/WorkspaceManager.java @@ -0,0 +1,155 @@ +package com.ss.builder.manager; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static com.ss.rlib.common.util.Utils.get; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.model.workspace.Workspace; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.manager.InitializeManager; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +/** + * The class to manage workspaces. + * + * @author JavaSaBr + */ +public class WorkspaceManager { + + public static final String FOLDER_EDITOR = ".jmonkeybuilder"; + public static final String FILE_WORKSPACE = "workspace"; + + @Nullable + private static WorkspaceManager instance; + + @FromAnyThread + public static @NotNull WorkspaceManager getInstance() { + if (instance == null) instance = new WorkspaceManager(); + return instance; + } + + /** + * The table of workspaces. + */ + @NotNull + private final ObjectDictionary workspaces; + + private WorkspaceManager() { + InitializeManager.valid(getClass()); + this.workspaces = DictionaryFactory.newObjectDictionary(); + } + + /** + * Get the table of workspaces. + * + * @return the table of workspaces. + */ + @FromAnyThread + private @NotNull ObjectDictionary getWorkspaces() { + return workspaces; + } + + /** + * Get the current workspace. + * + * @return the current workspace or null. + */ + @FromAnyThread + public @Nullable Workspace getCurrentWorkspace() { + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + + if (currentAsset == null) { + return null; + } + + return getWorkspace(currentAsset); + } + + /** + * Get the optional value of current workspace. + * + * @return the optional value of current workspace. + */ + @FromAnyThread + public @NotNull Optional getCurrentWorkspaceOpt() { + return Optional.ofNullable(getCurrentWorkspace()); + } + + /** + * Require the current workspace. + * + * @return the current workspace. + */ + @FromAnyThread + public @NotNull Workspace requiredCurrentWorkspace() { + return notNull(getCurrentWorkspace()); + } + + /** + * Get the workspace for the asset folder. + * + * @return the workspace. + */ + @FromAnyThread + private synchronized @NotNull Workspace getWorkspace(@NotNull Path assetFolder) { + + var workspaces = getWorkspaces(); + var exists = workspaces.get(assetFolder); + if (exists != null) { + return exists; + } + + var workspaceFile = assetFolder.resolve(FOLDER_EDITOR) + .resolve(FILE_WORKSPACE); + + if (!Files.exists(workspaceFile)) { + + var workspace = new Workspace(); + workspace.notifyRestored(); + workspace.setAssetFolder(assetFolder); + workspaces.put(assetFolder, workspace); + + return workspace; + } + + Workspace workspace; + try { + workspace = EditorUtils.deserialize(notNull(get(workspaceFile, Files::readAllBytes))); + } catch (RuntimeException e) { + workspace = new Workspace(); + } + + workspace.notifyRestored(); + workspace.setAssetFolder(assetFolder); + workspaces.put(assetFolder, workspace); + + return workspace; + } + + /** + * Clear all workspaces. + */ + @FromAnyThread + public synchronized void clear() { + var workspaces = getWorkspaces(); + workspaces.forEach(Workspace::clear); + workspaces.forEach((path, workspace) -> workspace.save(true)); + } + + /** + * Save all workspaces. + */ + @FromAnyThread + public synchronized void save() { + getWorkspaces().forEach((path, workspace) -> workspace.save(true)); + } +} diff --git a/src/main/java/com/ss/builder/model/EditorCamera.java b/src/main/java/com/ss/builder/model/EditorCamera.java new file mode 100644 index 00000000..82663bcf --- /dev/null +++ b/src/main/java/com/ss/builder/model/EditorCamera.java @@ -0,0 +1,703 @@ +package com.ss.builder.model; + +import static java.lang.Math.*; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.input.*; +import com.jme3.input.controls.*; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.Config; +import com.ss.builder.util.JmeUtils; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.Config; +import com.ss.builder.util.JmeUtils; +import com.ss.rlib.common.geom.util.AngleUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerLevel; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ObjectUtils; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +/** + * The implementation of editor camera based on {@link ChaseCamera}. + * + * @author JavaSaBr + */ +public class EditorCamera extends AbstractControl implements ActionListener, AnalogListener { + + private static final Logger LOGGER = LoggerManager.getLogger(EditorCamera.class); + + private static final String CAMERA_TOGGLE_ROTATE = "jMB." + CameraInput.CHASECAM_TOGGLEROTATE; + private static final String CAMERA_DOWN = "jMB." + CameraInput.CHASECAM_DOWN; + private static final String CAMERA_UP = "jMB." + CameraInput.CHASECAM_UP; + private static final String CAMERA_MOVE_LEFT = "jMB." + CameraInput.CHASECAM_MOVELEFT; + private static final String CAMERA_MOVE_RIGHT = "jMB." + CameraInput.CHASECAM_MOVERIGHT; + private static final String CAMERA_ZOOM_IN = "jMB." + CameraInput.CHASECAM_ZOOMIN; + private static final String CAMERA_ZOOM_OUT = "jMB." + CameraInput.CHASECAM_ZOOMOUT; + + private static final String[] ALL_INPUTS = { + CAMERA_TOGGLE_ROTATE, + CAMERA_DOWN, + CAMERA_UP, + CAMERA_MOVE_LEFT, + CAMERA_MOVE_RIGHT, + CAMERA_ZOOM_IN, + CAMERA_ZOOM_OUT + }; + + private static final ObjectDictionary TRIGGERS = ObjectDictionary.of( + CAMERA_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, false), + CAMERA_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, true), + CAMERA_ZOOM_IN, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false), + CAMERA_ZOOM_OUT, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true), + CAMERA_MOVE_LEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true), + CAMERA_MOVE_RIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false), + CAMERA_TOGGLE_ROTATE, new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE) + ); + + public enum Perspective { + BACK, + RIGHT, + TOP, + BOTTOM + } + + public enum Direction { + LEFT, + RIGHT, + TOP, + BOTTOM + } + + @NotNull + private final Vector3f position; + + @NotNull + private final Vector3f targetLocation; + + @NotNull + private final Vector3f initialUpVec; + + @NotNull + private final Vector3f prevPos; + + @NotNull + private final Vector3f lookAtOffset; + + @NotNull + private final Camera camera; + + @Nullable + private InputManager inputManager; + + private float minDistance; + private float maxDistance; + private float distance; + + private float rotationSpeed; + + private float hRotation; + private float vRotation; + + private float zoomSensitivity; + + private float targetHRotation = hRotation; + private float targetVRotation = vRotation; + + private float targetDistance; + + private boolean dragToRotate; + private boolean hideCursorOnRotate; + + private boolean canRotate; + private boolean lockRotation; + + public EditorCamera(@NotNull Camera camera, @NotNull Spatial target) { + this(camera); + target.addControl(this); + } + + public EditorCamera(@NotNull Camera camera) { + this.camera = camera; + this.initialUpVec = Vector3f.UNIT_Y.clone(); + this.position = new Vector3f(); + this.targetLocation = new Vector3f(); + this.lookAtOffset = new Vector3f(); + this.prevPos = new Vector3f(); + this.minDistance = 1.0f; + this.maxDistance = 40.0f; + this.distance = 20; + this.rotationSpeed = 1.0f; + this.hRotation = 0; + this.zoomSensitivity = 2f; + this.vRotation = FastMath.PI / 6; + this.targetDistance = distance; + this.enabled = true; + this.dragToRotate = true; + this.hideCursorOnRotate = true; + } + + /** + * Get the current camera direction. + * + * @return the current direction. + */ + @JmeThread + public @NotNull Vector3f getDirection() { + return camera.getDirection(new Vector3f()); + } + + /** + * Get the current camera direction to left side. + * + * @return the current direction to left side. + */ + @JmeThread + public @NotNull Vector3f getLeft() { + return camera.getLeft(new Vector3f()); + } + + /** + * Rotate this camera to the direction by the value. + * + * @param direction the direction. + * @param value the value. + */ + @JmeThread + public void rotateTo(@NotNull Direction direction, float value) { + + var hRotation = AngleUtils.radiansToDegree(targetHRotation); + var vRotation = AngleUtils.radiansToDegree(targetVRotation); + + if (direction == Direction.LEFT) { + hRotation += value; + } else if (direction == Direction.RIGHT) { + hRotation -= value; + } else if (direction == Direction.TOP) { + vRotation += value; + } else if (direction == Direction.BOTTOM) { + vRotation -= value; + } + + targetHRotation = AngleUtils.degreeToRadians(hRotation); + targetVRotation = AngleUtils.degreeToRadians(vRotation); + } + + /** + * Rotate this camera to the perspective. + * + * @param perspective the perspective. + */ + @JmeThread + public void rotateTo(@NotNull Perspective perspective) { + + var hRotation = AngleUtils.degreeToRadians(90); + var vRotation = AngleUtils.degreeToRadians(0); + + if (perspective == Perspective.BACK) { + hRotation = AngleUtils.degreeToRadians(-90); + } else if (perspective == Perspective.RIGHT) { + hRotation = AngleUtils.degreeToRadians(180); + } else if (perspective == Perspective.BOTTOM) { + vRotation = AngleUtils.degreeToRadians(90); + } else if (perspective == Perspective.TOP) { + vRotation = AngleUtils.degreeToRadians(-90); + } + + targetHRotation = hRotation; + targetVRotation = vRotation; + } + + /** + * Get the input manager. + * + * @return the input manager + */ + @JmeThread + private @NotNull InputManager getInputManager() { + return ObjectUtils.notNull(inputManager); + } + + @Override + @JmeThread + public @NotNull Spatial getSpatial() { + return ObjectUtils.notNull(super.getSpatial()); + } + + /** + * Set the target rotation. + * + * @param targetHRotation the target rotation. + */ + @JmeThread + public void setTargetHRotation(float targetHRotation) { + this.targetHRotation = targetHRotation; + } + + /** + * Set the target vertical rotation. + * + * @param targetVRotation the target vertical rotation. + */ + @JmeThread + public void setTargetVRotation(float targetVRotation) { + this.targetVRotation = targetVRotation; + } + + /** + * Set the target distance. + * + * @param targetDistance the target distance. + */ + @JmeThread + public void setTargetDistance(float targetDistance) { + this.targetDistance = targetDistance; + } + + /** + * Get the target distance. + * + * @return the target distance. + */ + @JmeThread + public float getTargetDistance() { + return targetDistance; + } + + @Override + @JmeThread + public void onAction(@NotNull String name, boolean keyPressed, float tpf) { + + if (!enabled || !dragToRotate) { + return; + } else if (!CAMERA_TOGGLE_ROTATE.equals(name)) { + return; + } + + if (Config.DEV_CAMERA_DEBUG) { + LOGGER.debug(this, name, keyPressed, + (action, pressed) -> "Action[" + action + "], pressed[" + pressed + "]"); + } + + canRotate = keyPressed; + + if (hideCursorOnRotate) { + getInputManager().setCursorVisible(!keyPressed); + } + } + + /** + * Set true to lock rotation. + * + * @param lockRotation true to lock rotation. + */ + @JmeThread + public void setLockRotation(boolean lockRotation) { + + if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { + LOGGER.debug(this, "Set lock rotation is: " + lockRotation); + } + + this.lockRotation = lockRotation; + } + + @Override + @JmeThread + public void onAnalog(@NotNull String name, float value, float tpf) { + + if (!enabled) { + return; + } + + if (name.equals(CAMERA_MOVE_LEFT) && !lockRotation) { + hRotateCamera(-value * 3); + } else if (name.equals(CAMERA_MOVE_RIGHT) && !lockRotation) { + hRotateCamera(value * 3); + } else if (name.equals(CAMERA_UP) && !lockRotation) { + vRotateCamera(value * 3); + } else if (name.equals(CAMERA_DOWN) && !lockRotation) { + vRotateCamera(-value * 3); + } else if (name.equals(CAMERA_ZOOM_IN)) { + zoomCamera(-value); + } else if (name.equals(CAMERA_ZOOM_OUT)) { + zoomCamera(value); + } + } + + /** + * Register inputs with the input manager. + * + * @param inputManager the input manager. + */ + @JmeThread + public void registerInput(@NotNull InputManager inputManager) { + this.inputManager = inputManager; + + TRIGGERS.forEach(inputManager, JmeUtils::addMapping); + + inputManager.addListener(this, ALL_INPUTS); + } + + /** + * Unregister input. + * + * @param inputManager the input manager + */ + @JmeThread + public void unregisterInput(@NotNull InputManager inputManager) { + inputManager.removeListener(this); + } + + /** + * Compute position. + */ + private void computePosition() { + + var highDistance = distance * FastMath.sin((FastMath.PI / 2) - vRotation); + + var x = highDistance * FastMath.cos(hRotation); + var y = distance * FastMath.sin(vRotation); + var z = highDistance * FastMath.sin(hRotation); + + position.set(x, y, z) + .addLocal(getSpatial().getWorldTranslation()); + } + + /** + * Rotate this camera in horizontal. + * + * @param value the value. + */ + private void hRotateCamera(float value) { + + if (!canRotate || !enabled) { + return; + } + + targetHRotation += value * rotationSpeed; + } + + /** + * Zoom camera. + * + * @param value the value. + */ + private void zoomCamera(float value) { + + if (!enabled) { + return; + } + + targetDistance += value * zoomSensitivity * sqrt(targetDistance); + targetDistance = max(min(targetDistance, maxDistance), minDistance); + } + + /** + * Vertical rotate camera. + * + * @param value the value + */ + private void vRotateCamera(float value) { + + if (!canRotate || !enabled) { + return; + } + + targetVRotation += value * rotationSpeed; + } + + @Override + protected void controlUpdate(float tpf) { + + targetLocation.set(getSpatial().getWorldTranslation()) + .addLocal(lookAtOffset); + + vRotation = targetVRotation; + hRotation = targetHRotation; + distance = targetDistance; + + computePosition(); + + camera.setLocation(position.addLocal(lookAtOffset)); + + // keeping track on the previous position of the target + prevPos.set(targetLocation); + + // the camera looks at the target + camera.lookAt(targetLocation, initialUpVec); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } + + @Override + @JmeThread + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (!enabled) { + canRotate = false; // reset this flag in-case it was on before + } + } + + /** + * Returns the max zoom distance of the camera (default is 40) + * + * @return maxDistance max distance + */ + public float getMaxDistance() { + return maxDistance; + } + + /** + * Sets the max zoom distance of the camera (default is 40) + * + * @param maxDistance the max distance + */ + public void setMaxDistance(float maxDistance) { + this.maxDistance = maxDistance; + if (maxDistance < distance) { + zoomCamera(maxDistance - distance); + } + } + + /** + * Returns the min zoom distance of the camera (default is 1) + * + * @return minDistance min distance + */ + public float getMinDistance() { + return minDistance; + } + + /** + * Sets the min zoom distance of the camera (default is 1) + * + * @param minDistance the min distance + */ + public void setMinDistance(float minDistance) { + this.minDistance = minDistance; + if (minDistance > distance) { + zoomCamera(distance - minDistance); + } + } + + /** + * clone this camera for a spatial + */ + @Override + public Control cloneForSpatial(Spatial spatial) { + + var editorCamera = new EditorCamera(camera, spatial); + editorCamera.setMaxDistance(getMaxDistance()); + editorCamera.setMinDistance(getMinDistance()); + + if (inputManager != null) { + editorCamera.registerInput(inputManager); + } + + return editorCamera; + } + + /** + * Sets the spacial for the camera control, should only be used internally + */ + public void setSpatial(@Nullable Spatial spatial) { + super.setSpatial(spatial); + + if (spatial == null) { + return; + } + + computePosition(); + prevPos.set(spatial.getWorldTranslation()); + camera.setLocation(position); + } + + /** + * Write the camera + * + * @param exporter the exporter + */ + public void write(@NotNull JmeExporter exporter) { + throw new UnsupportedOperationException("remove ChaseCamera before saving"); + } + + /** + * Read the camera + */ + public void read(@NotNull JmeImporter importer) throws IOException { + var ic = importer.getCapsule(this); + maxDistance = ic.readFloat("maxDistance", 40); + minDistance = ic.readFloat("minDistance", 1); + } + + /** + * returns the zoom sensitivity + * + * @return the zoom sensitivity + */ + public float getZoomSensitivity() { + return zoomSensitivity; + } + + /** + * Sets the zoom sensitivity, the lower the value, the slower the camera will zoom in and out. default is 2. + * + * @param zoomSensitivity the zoom sensitivity + */ + public void setZoomSensitivity(float zoomSensitivity) { + this.zoomSensitivity = zoomSensitivity; + } + + /** + * Returns the rotation speed when the mouse is moved. + * + * @return the rotation speed when the mouse is moved. + */ + public float getRotationSpeed() { + return rotationSpeed; + } + + /** + * Sets the rotate amount when user moves his mouse, the lower the value, the slower the camera will rotate. + * default is 1. + * + * @param rotationSpeed Rotation speed on mouse movement, default is 1. + */ + public void setRotationSpeed(float rotationSpeed) { + this.rotationSpeed = rotationSpeed; + } + + /** + * Sets the default distance at start of applicaiton + * + * @param defaultDistance the default distance + */ + public void setDefaultDistance(float defaultDistance) { + distance = defaultDistance; + targetDistance = distance; + } + + /** + * sets the default horizontal rotation in radian of the camera at start of the application + * + * @param angleInRad the angle in rad + */ + public void setDefaultHorizontalRotation(float angleInRad) { + hRotation = angleInRad; + targetHRotation = angleInRad; + } + + /** + * sets the default vertical rotation in radian of the camera at start of the application + * + * @param angleInRad the angle in rad + */ + public void setDefaultVerticalRotation(float angleInRad) { + vRotation = angleInRad; + targetVRotation = angleInRad; + } + + /** + * Is drag to rotate boolean. + * + * @return If drag to rotate feature is enabled. + * @see FlyByCamera#setDragToRotate(boolean) FlyByCamera#setDragToRotate(boolean)FlyByCamera#setDragToRotate(boolean) + */ + public boolean isDragToRotate() { + return dragToRotate; + } + + /** + * Sets drag to rotate. + * + * @param dragToRotate When true, the user must hold the mouse button and drag over the screen to rotate the camera, + * and the cursor is visible until dragged. Otherwise, the cursor is invisible at all times and + * holding the mouse button is not needed to rotate the camera. This feature is disabled by + * default. + */ + public void setDragToRotate(boolean dragToRotate) { + this.dragToRotate = dragToRotate; + this.canRotate = !dragToRotate; + + if (inputManager != null) { + inputManager.setCursorVisible(dragToRotate); + } + } + + /** + * return the current distance from the camera to the target + * + * @return the distance to target + */ + public float getDistanceToTarget() { + return distance; + } + + /** + * returns the current horizontal rotation around the target in radians + * + * @return the horizontal rotation + */ + public float getHRotation() { + return hRotation; + } + + /** + * returns the current vertical rotation around the target in radians. + * + * @return the vertical rotation + */ + public float getVRotation() { + return vRotation; + } + + /** + * returns the offset from the target's position where the camera looks at + * + * @return the look at offset + */ + public Vector3f getLookAtOffset() { + return lookAtOffset; + } + + /** + * Sets the offset from the target's position where the camera looks at + * + * @param lookAtOffset the look at offset + */ + public void setLookAtOffset(Vector3f lookAtOffset) { + this.lookAtOffset.set(lookAtOffset); + } + + /** + * Is hide cursor on rotate boolean. + * + * @return the boolean + */ + public boolean isHideCursorOnRotate() { + return hideCursorOnRotate; + } + + /** + * Sets hide cursor on rotate. + * + * @param hideCursorOnRotate the hide cursor on rotate + */ + public void setHideCursorOnRotate(boolean hideCursorOnRotate) { + this.hideCursorOnRotate = hideCursorOnRotate; + } +} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/model/UObject.java b/src/main/java/com/ss/builder/model/UObject.java similarity index 87% rename from src/main/java/com/ss/editor/model/UObject.java rename to src/main/java/com/ss/builder/model/UObject.java index 2b955038..17e2c5c5 100644 --- a/src/main/java/com/ss/editor/model/UObject.java +++ b/src/main/java/com/ss/builder/model/UObject.java @@ -1,4 +1,4 @@ -package com.ss.editor.model; +package com.ss.builder.model; /** * The interface to implement uniq object. diff --git a/src/main/java/com/ss/editor/model/editor/Editing3DProvider.java b/src/main/java/com/ss/builder/model/editor/Editing3DProvider.java similarity index 81% rename from src/main/java/com/ss/editor/model/editor/Editing3DProvider.java rename to src/main/java/com/ss/builder/model/editor/Editing3DProvider.java index 4b2dd9fc..50870a16 100644 --- a/src/main/java/com/ss/editor/model/editor/Editing3DProvider.java +++ b/src/main/java/com/ss/builder/model/editor/Editing3DProvider.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.editor; +package com.ss.builder.model.editor; /** * The interface to implement a provider things to edit 3D scene. diff --git a/src/main/java/com/ss/editor/model/editor/Editor3DProvider.java b/src/main/java/com/ss/builder/model/editor/Editor3DProvider.java similarity index 79% rename from src/main/java/com/ss/editor/model/editor/Editor3DProvider.java rename to src/main/java/com/ss/builder/model/editor/Editor3DProvider.java index 212bd847..044186db 100644 --- a/src/main/java/com/ss/editor/model/editor/Editor3DProvider.java +++ b/src/main/java/com/ss/builder/model/editor/Editor3DProvider.java @@ -1,7 +1,8 @@ -package com.ss.editor.model.editor; +package com.ss.builder.model.editor; import com.jme3.scene.Node; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/editor/model/editor/ModelEditingProvider.java b/src/main/java/com/ss/builder/model/editor/ModelEditingProvider.java similarity index 80% rename from src/main/java/com/ss/editor/model/editor/ModelEditingProvider.java rename to src/main/java/com/ss/builder/model/editor/ModelEditingProvider.java index ac1423d9..f36a4d6d 100644 --- a/src/main/java/com/ss/editor/model/editor/ModelEditingProvider.java +++ b/src/main/java/com/ss/builder/model/editor/ModelEditingProvider.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.editor; +package com.ss.builder.model.editor; /** * The interface to implement a provider to edit models. diff --git a/src/main/java/com/ss/editor/model/editor/Painting3DProvider.java b/src/main/java/com/ss/builder/model/editor/Painting3DProvider.java similarity index 81% rename from src/main/java/com/ss/editor/model/editor/Painting3DProvider.java rename to src/main/java/com/ss/builder/model/editor/Painting3DProvider.java index 97e0672b..325fdff8 100644 --- a/src/main/java/com/ss/editor/model/editor/Painting3DProvider.java +++ b/src/main/java/com/ss/builder/model/editor/Painting3DProvider.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.editor; +package com.ss.builder.model.editor; /** * The interface to implement a provider things to paint 3D. diff --git a/src/main/java/com/ss/editor/model/node/layer/LayersRoot.java b/src/main/java/com/ss/builder/model/node/layer/LayersRoot.java similarity index 78% rename from src/main/java/com/ss/editor/model/node/layer/LayersRoot.java rename to src/main/java/com/ss/builder/model/node/layer/LayersRoot.java index 1c66b0a8..76a79df1 100644 --- a/src/main/java/com/ss/editor/model/node/layer/LayersRoot.java +++ b/src/main/java/com/ss/builder/model/node/layer/LayersRoot.java @@ -1,7 +1,9 @@ -package com.ss.editor.model.node.layer; +package com.ss.builder.model.node.layer; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/node/material/ColorsSettings.java b/src/main/java/com/ss/builder/model/node/material/ColorsSettings.java similarity index 87% rename from src/main/java/com/ss/editor/model/node/material/ColorsSettings.java rename to src/main/java/com/ss/builder/model/node/material/ColorsSettings.java index a41349cf..4282e2e5 100644 --- a/src/main/java/com/ss/editor/model/node/material/ColorsSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/ColorsSettings.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/node/material/MaterialSettings.java b/src/main/java/com/ss/builder/model/node/material/MaterialSettings.java similarity index 79% rename from src/main/java/com/ss/editor/model/node/material/MaterialSettings.java rename to src/main/java/com/ss/builder/model/node/material/MaterialSettings.java index 3ab3d089..9bae3966 100644 --- a/src/main/java/com/ss/editor/model/node/material/MaterialSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/MaterialSettings.java @@ -1,7 +1,8 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/ss/editor/model/node/material/OtherSettings.java b/src/main/java/com/ss/builder/model/node/material/OtherSettings.java similarity index 87% rename from src/main/java/com/ss/editor/model/node/material/OtherSettings.java rename to src/main/java/com/ss/builder/model/node/material/OtherSettings.java index df3d250a..56b88227 100644 --- a/src/main/java/com/ss/editor/model/node/material/OtherSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/OtherSettings.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/node/material/RenderSettings.java b/src/main/java/com/ss/builder/model/node/material/RenderSettings.java similarity index 87% rename from src/main/java/com/ss/editor/model/node/material/RenderSettings.java rename to src/main/java/com/ss/builder/model/node/material/RenderSettings.java index 15e34fdd..3b6ed6b0 100644 --- a/src/main/java/com/ss/editor/model/node/material/RenderSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/RenderSettings.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/node/material/RootMaterialSettings.java b/src/main/java/com/ss/builder/model/node/material/RootMaterialSettings.java similarity index 87% rename from src/main/java/com/ss/editor/model/node/material/RootMaterialSettings.java rename to src/main/java/com/ss/builder/model/node/material/RootMaterialSettings.java index b5789a54..c78cfcda 100644 --- a/src/main/java/com/ss/editor/model/node/material/RootMaterialSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/RootMaterialSettings.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/node/material/TexturesSettings.java b/src/main/java/com/ss/builder/model/node/material/TexturesSettings.java similarity index 87% rename from src/main/java/com/ss/editor/model/node/material/TexturesSettings.java rename to src/main/java/com/ss/builder/model/node/material/TexturesSettings.java index d628b39a..f62b2f57 100644 --- a/src/main/java/com/ss/editor/model/node/material/TexturesSettings.java +++ b/src/main/java/com/ss/builder/model/node/material/TexturesSettings.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.node.material; +package com.ss.builder.model.node.material; import com.jme3.material.Material; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/scene/EditorAudioNode.java b/src/main/java/com/ss/builder/model/scene/EditorAudioNode.java similarity index 93% rename from src/main/java/com/ss/editor/model/scene/EditorAudioNode.java rename to src/main/java/com/ss/builder/model/scene/EditorAudioNode.java index 321b0243..990e1a56 100644 --- a/src/main/java/com/ss/editor/model/scene/EditorAudioNode.java +++ b/src/main/java/com/ss/builder/model/scene/EditorAudioNode.java @@ -1,15 +1,17 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; -import static com.ss.editor.util.GeomUtils.getDirection; +import static com.ss.builder.util.GeomUtils.getDirection; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.audio.AudioNode; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/model/scene/EditorLightNode.java b/src/main/java/com/ss/builder/model/scene/EditorLightNode.java similarity index 95% rename from src/main/java/com/ss/editor/model/scene/EditorLightNode.java rename to src/main/java/com/ss/builder/model/scene/EditorLightNode.java index a7c735ca..60c28b61 100644 --- a/src/main/java/com/ss/editor/model/scene/EditorLightNode.java +++ b/src/main/java/com/ss/builder/model/scene/EditorLightNode.java @@ -1,6 +1,6 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; -import static com.ss.editor.util.GeomUtils.getDirection; +import static com.ss.builder.util.GeomUtils.getDirection; import static com.ss.rlib.common.util.ObjectUtils.notNull; import com.jme3.light.DirectionalLight; import com.jme3.light.Light; @@ -10,9 +10,11 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.util.LocalObjects; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.LocalObjects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/model/scene/EditorPresentableNode.java b/src/main/java/com/ss/builder/model/scene/EditorPresentableNode.java new file mode 100644 index 00000000..532b2d6b --- /dev/null +++ b/src/main/java/com/ss/builder/model/scene/EditorPresentableNode.java @@ -0,0 +1,236 @@ +package com.ss.builder.model.scene; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.ScenePresentable; +import com.ss.editor.extension.scene.ScenePresentable.PresentationType; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The node to present and edit objects on a scene which aren't models. + * + * @author JavaSaBr + */ +public class EditorPresentableNode extends Node { + + private class EditedNode extends Node implements VisibleOnlyWhenSelected, NoSelection, WrapperNode { + + private EditedNode(@NotNull String name) { + super(name); + } + + @Override + @FromAnyThread + public @NotNull Object getWrappedObject() { + return notNull(getObject()); + } + + @Override + @JmeThread + public void setCullHint(CullHint hint) { + super.setCullHint(hint); + notNull(getModel()).setCullHint(hint); + } + } + + /** + * The node to edit. + */ + @NotNull + private final EditedNode editedNode; + + /** + * The presented object. + */ + @Nullable + private ScenePresentable object; + + /** + * Previous presentation type. + */ + @Nullable + private PresentationType prevPresentationType; + + /** + * The view model. + */ + @Nullable + private Geometry model; + + public EditorPresentableNode() { + this.editedNode = new EditedNode("EditedNode"); + attachChild(editedNode); + } + + /** + * Set the object. + * + * @param object the object. + */ + @JmeThread + public void setObject(@Nullable ScenePresentable object) { + this.object = object; + } + + /** + * Get the edited node. + * + * @return the edited node. + */ + @JmeThread + public @NotNull Node getEditedNode() { + return editedNode; + } + + /** + * Get the object. + * + * @return the object. + */ + @JmeThread + public @Nullable ScenePresentable getObject() { + return object; + } + + /** + * Get the model. + * + * @return the model. + */ + @JmeThread + public @Nullable Geometry getModel() { + return model; + } + + /** + * Set the model. + * + * @param model the model. + */ + @JmeThread + public void setModel(@Nullable Geometry model) { + this.model = model; + } + + @Override + @JmeThread + public void updateGeometricState() { + + var object = getObject(); + + if (object != null) { + var editedNode = getEditedNode(); + object.setRotation(editedNode.getLocalRotation()); + object.setLocation(editedNode.getLocalTranslation()); + object.setScale(editedNode.getLocalScale()); + } + + super.updateGeometricState(); + } + + /** + * Synchronize this node with presented object. + */ + @JmeThread + public void sync() { + + var object = notNull(getObject()); + + var editedNode = getEditedNode(); + editedNode.setLocalRotation(object.getRotation()); + editedNode.setLocalTranslation(object.getLocation()); + editedNode.setLocalScale(object.getScale()); + } + + /** + * Update position and rotation of a model. + */ + @JmeThread + public void updateModel() { + + var object = getObject(); + var model = getModel(); + + if (model == null || object == null) { + return; + } + + // TODO implement getting parent + /*final Node parent = object.getParent(); + + if (parent != null) { + setLocalTranslation(parent.getWorldTranslation()); + setLocalRotation(parent.getWorldRotation()); + setLocalScale(parent.getWorldScale()); + }*/ + + var editedNode = getEditedNode(); + + model.setLocalTranslation(editedNode.getWorldTranslation()); + model.setLocalRotation(editedNode.getWorldRotation()); + model.setLocalScale(editedNode.getWorldScale()); + } + + /** + * Update a geometry of presentation. + */ + @JmeThread + public void updateGeometry() { + + var presentationType = notNull(getObject()).getPresentationType(); + if (presentationType == prevPresentationType) { + return; + } + + var prevModel = getModel(); + var newModel = createGeometry(presentationType); + + setModel(newModel); + + if (prevModel != null) { + Node parent = prevModel.getParent(); + prevModel.removeFromParent(); + if (parent != null) { + parent.attachChild(newModel); + } + } + + this.prevPresentationType = presentationType; + } + + @JmeThread + private @NotNull Geometry createGeometry(@NotNull PresentationType presentationType) { + + var material = new Material(EditorUtils.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor("Color", ColorRGBA.Yellow); + material.getAdditionalRenderState().setWireframe(true); + + Geometry geometry; + + switch (presentationType) { + case SPHERE: { + geometry = new Geometry("Sphere", new Sphere(8, 8, 1)); + break; + } + default: { + geometry = new Geometry("Box", new Box(1, 1, 1)); + } + } + + geometry.setMaterial(material); + + return geometry; + } +} diff --git a/src/main/java/com/ss/editor/model/scene/NoSelection.java b/src/main/java/com/ss/builder/model/scene/NoSelection.java similarity index 79% rename from src/main/java/com/ss/editor/model/scene/NoSelection.java rename to src/main/java/com/ss/builder/model/scene/NoSelection.java index 0a5d1799..91c819d1 100644 --- a/src/main/java/com/ss/editor/model/scene/NoSelection.java +++ b/src/main/java/com/ss/builder/model/scene/NoSelection.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; /** * The interface to mark an object that it should be without seleciton. diff --git a/src/main/java/com/ss/editor/model/scene/SceneAppStatesNode.java b/src/main/java/com/ss/builder/model/scene/SceneAppStatesNode.java similarity index 81% rename from src/main/java/com/ss/editor/model/scene/SceneAppStatesNode.java rename to src/main/java/com/ss/builder/model/scene/SceneAppStatesNode.java index e59de1ba..fa5b9959 100644 --- a/src/main/java/com/ss/editor/model/scene/SceneAppStatesNode.java +++ b/src/main/java/com/ss/builder/model/scene/SceneAppStatesNode.java @@ -1,7 +1,8 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; import com.jme3.util.SafeArrayList; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.SceneAppState; import org.jetbrains.annotations.NotNull; @@ -19,7 +20,7 @@ public class SceneAppStatesNode { @NotNull private final SceneNode sceneNode; - public SceneAppStatesNode(@NotNull final SceneNode sceneNode) { + public SceneAppStatesNode(@NotNull SceneNode sceneNode) { this.sceneNode = sceneNode; } diff --git a/src/main/java/com/ss/editor/model/scene/SceneFiltersNode.java b/src/main/java/com/ss/builder/model/scene/SceneFiltersNode.java similarity index 87% rename from src/main/java/com/ss/editor/model/scene/SceneFiltersNode.java rename to src/main/java/com/ss/builder/model/scene/SceneFiltersNode.java index 34f2c297..6a8f4a2c 100644 --- a/src/main/java/com/ss/editor/model/scene/SceneFiltersNode.java +++ b/src/main/java/com/ss/builder/model/scene/SceneFiltersNode.java @@ -1,7 +1,8 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; import com.jme3.util.SafeArrayList; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.filter.SceneFilter; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/model/scene/VisibleOnlyWhenSelected.java b/src/main/java/com/ss/builder/model/scene/VisibleOnlyWhenSelected.java similarity index 81% rename from src/main/java/com/ss/editor/model/scene/VisibleOnlyWhenSelected.java rename to src/main/java/com/ss/builder/model/scene/VisibleOnlyWhenSelected.java index e2ca8fb0..3bdf89e9 100644 --- a/src/main/java/com/ss/editor/model/scene/VisibleOnlyWhenSelected.java +++ b/src/main/java/com/ss/builder/model/scene/VisibleOnlyWhenSelected.java @@ -1,4 +1,4 @@ -package com.ss.editor.model.scene; +package com.ss.builder.model.scene; /** * The interface to mak object that it need to be visible only when it's selected. diff --git a/src/main/java/com/ss/builder/model/scene/WrapperNode.java b/src/main/java/com/ss/builder/model/scene/WrapperNode.java new file mode 100644 index 00000000..c5c9f83c --- /dev/null +++ b/src/main/java/com/ss/builder/model/scene/WrapperNode.java @@ -0,0 +1,16 @@ +package com.ss.builder.model.scene; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to mark some object about that the object has another object to update. + * + * @author JavaSaBr + */ +public interface WrapperNode { + + @FromAnyThread + @NotNull Object getWrappedObject(); +} diff --git a/src/main/java/com/ss/builder/model/undo/EditorOperation.java b/src/main/java/com/ss/builder/model/undo/EditorOperation.java new file mode 100644 index 00000000..6f49a997 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/EditorOperation.java @@ -0,0 +1,32 @@ +package com.ss.builder.model.undo; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; + +import org.jetbrains.annotations.NotNull; + +/** + * The interface for implementing an operation in an editor. + * + * @author JavaSabr + */ +public interface EditorOperation { + + /** + * Redo this operation for the editor. + * + * @param editor the editor. + */ + @FxThread + default void redo(@NotNull UndoableEditor editor) { + } + + /** + * Undo this operation for the editor. + * + * @param editor the editor. + */ + @FxThread + default void undo(@NotNull UndoableEditor editor) { + } +} diff --git a/src/main/java/com/ss/editor/model/undo/EditorOperationControl.java b/src/main/java/com/ss/builder/model/undo/EditorOperationControl.java similarity index 94% rename from src/main/java/com/ss/editor/model/undo/EditorOperationControl.java rename to src/main/java/com/ss/builder/model/undo/EditorOperationControl.java index b8544613..f3b484c6 100644 --- a/src/main/java/com/ss/editor/model/undo/EditorOperationControl.java +++ b/src/main/java/com/ss/builder/model/undo/EditorOperationControl.java @@ -1,8 +1,11 @@ -package com.ss.editor.model.undo; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; +package com.ss.builder.model.undo; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import javafx.application.Platform; diff --git a/src/main/java/com/ss/builder/model/undo/UndoableEditor.java b/src/main/java/com/ss/builder/model/undo/UndoableEditor.java new file mode 100644 index 00000000..8d80aaec --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/UndoableEditor.java @@ -0,0 +1,38 @@ +package com.ss.builder.model.undo; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; + +/** + * The interface to implement an undoable editor. + * + * @author JavaSaBr + */ +public interface UndoableEditor { + + /** + * Increment changes count. + */ + @FxThread + void incrementChange(); + + /** + * Decrement changes count. + */ + @FxThread + void decrementChange(); + + /** + * Redo the last operation. + */ + @FromAnyThread + void redo(); + + /** + * Undo the last operation. + */ + @FromAnyThread + void undo(); +} diff --git a/src/main/java/com/ss/builder/model/undo/editor/ChangeConsumer.java b/src/main/java/com/ss/builder/model/undo/editor/ChangeConsumer.java new file mode 100644 index 00000000..7b0731a0 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/editor/ChangeConsumer.java @@ -0,0 +1,156 @@ +package com.ss.builder.model.undo.editor; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.EditorOperation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The interface to notify about any changes. + * + * @author JavaSaBr + */ +public interface ChangeConsumer { + + /** + * Notify about an attempt to change the property from jME thread. + * + * @param object the object. + * @param propertyName the property name. + */ + @JmeThread + default void notifyJmePreChangeProperty(@NotNull Object object, @NotNull String propertyName) { + } + + /** + * Notify about changed the property from jME thread. + * + * @param object the object. + * @param propertyName the property name. + */ + @JmeThread + default void notifyJmeChangedProperty(@NotNull Object object, @NotNull String propertyName) { + } + + /** + * Notify about changed the object in the jME thread. + * + * @param object the object. + */ + @JmeThread + default void notifyJmeObjectChanged(@NotNull Object object) { + } + + /** + * Notify about changed the object in the Fx thread. + * + * @param object the object. + */ + @FxThread + default void notifyFxObjectChanged(@NotNull Object object) { + } + + /** + * Notify about changed property from jME thread. + * + * @param object the object + * @param propertyName the property name + */ + @FxThread + default void notifyFxChangeProperty(@NotNull Object object, @NotNull String propertyName) { + notifyFxChangeProperty(null, object, propertyName); + } + + /** + * Notify about changed property count in the object from FX thread. + * + * @param object the object + */ + @FxThread + default void notifyFxChangePropertyCount(@NotNull Object object) { + } + + /** + * Notify about changed property. + * + * @param parent the parent + * @param object the object + * @param propertyName the property name + */ + @FxThread + default void notifyFxChangeProperty(@Nullable Object parent, @NotNull Object object, @NotNull String propertyName) { + } + + /** + * Notify about added child from FX thread. + * + * @param parent the parent. + * @param added the added. + * @param index the index of position. + * @param needSelect true if need to select the child. + */ + @FxThread + default void notifyFxAddedChild(@NotNull Object parent, @NotNull Object added, int index, boolean needSelect) { + } + + /** + * Notify about removed child from FX thread. + * + * @param parent the parent + * @param removed the removed + */ + @FxThread + default void notifyFxRemovedChild(@NotNull Object parent, @NotNull Object removed) { + } + + /** + * Notify about replaced child from FX thread. + * + * @param parent the parent. + * @param oldChild the old child. + * @param newChild the new child. + * @param needExpand true of need to expand new node. + * @param needDeepExpand true of need to expand new node deeply. + */ + @FxThread + default void notifyFxReplaced( + @NotNull Object parent, + @Nullable Object oldChild, + @Nullable Object newChild, + boolean needExpand, + boolean needDeepExpand + ) { + } + + /** + * Notify about moved child from FX thread. + * + * @param prevParent the prev parent. + * @param newParent the new parent. + * @param child the child. + * @param index the index of position. + * @param needSelect true if need select this object. + */ + @FxThread + default void notifyFxMoved( + @NotNull Object prevParent, + @NotNull Object newParent, + @NotNull Object child, + int index, + boolean needSelect + ) { + } + + /** + * Execute the operation. + * + * @param operation the operation + */ + @FromAnyThread + void execute(@NotNull EditorOperation operation); +} diff --git a/src/main/java/com/ss/builder/model/undo/editor/ModelChangeConsumer.java b/src/main/java/com/ss/builder/model/undo/editor/ModelChangeConsumer.java new file mode 100644 index 00000000..1da2104d --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/editor/ModelChangeConsumer.java @@ -0,0 +1,22 @@ +package com.ss.builder.model.undo.editor; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import org.jetbrains.annotations.NotNull; + +/** + * The interface to notify about any changes of models. + * + * @author JavaSaBr + */ +public interface ModelChangeConsumer extends ChangeConsumer { + + /** + * Get the current model. + * + * @return the current model of the editor. + */ + @FxThread + @NotNull Spatial getCurrentModel(); +} diff --git a/src/main/java/com/ss/editor/model/undo/editor/SceneChangeConsumer.java b/src/main/java/com/ss/builder/model/undo/editor/SceneChangeConsumer.java similarity index 92% rename from src/main/java/com/ss/editor/model/undo/editor/SceneChangeConsumer.java rename to src/main/java/com/ss/builder/model/undo/editor/SceneChangeConsumer.java index f2cc66f5..186b7d7e 100644 --- a/src/main/java/com/ss/editor/model/undo/editor/SceneChangeConsumer.java +++ b/src/main/java/com/ss/builder/model/undo/editor/SceneChangeConsumer.java @@ -1,6 +1,7 @@ -package com.ss.editor.model.undo.editor; +package com.ss.builder.model.undo.editor; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.SceneAppState; import com.ss.editor.extension.scene.filter.SceneFilter; diff --git a/src/main/java/com/ss/builder/model/undo/impl/AbstractEditorOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AbstractEditorOperation.java new file mode 100644 index 00000000..cead6faf --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AbstractEditorOperation.java @@ -0,0 +1,187 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.EditorOperation; +import com.ss.builder.model.undo.UndoableEditor; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ClassUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of the {@link EditorOperation} to support a generic type of an editor. + * + * @param the change consumer's type. + * @author JavaSabr + */ +public abstract class AbstractEditorOperation implements EditorOperation { + + protected static final Logger LOGGER = LoggerManager.getLogger(EditorOperation.class); + + public AbstractEditorOperation() { + } + + @Override + @FxThread + public void redo(@NotNull UndoableEditor editor) { + redoImpl(ClassUtils.unsafeCast(editor)); + } + + /** + * Execute changes. + * + * @param editor the editor. + */ + @FxThread + protected void redoImpl(@NotNull E editor) { + startInFx(editor); + startRedoInFx(editor); + + ExecutorManager.getInstance() + .addJmeTask(() -> { + startInJme(editor); + redoInJme(editor); + endInJme(editor); + ExecutorManager.getInstance() + .addFxTask(() -> { + endRedoInFx(editor); + endInFx(editor); + }); + }); + } + + /** + * Start executing general changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void startInFx(@NotNull E editor) { + + } + + /** + * Finish executing general changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void endInFx(@NotNull E editor) { + + } + + /** + * Start executing general changes in jME thread. + * + * @param editor the editor. + */ + @JmeThread + protected void startInJme(@NotNull E editor) { + + } + + /** + * Finish executing general changes in jME thread. + * + * @param editor the editor. + */ + @JmeThread + protected void endInJme(@NotNull E editor) { + + } + + /** + * Start executing changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void startRedoInFx(@NotNull E editor) { + + } + + /** + * Execute changes in jME thread. + * + * @param editor the editor. + */ + @JmeThread + protected void redoInJme(@NotNull E editor) { + + } + + /** + * Finish executing changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void endRedoInFx(@NotNull E editor) { + + } + + + @Override + @FxThread + public void undo(@NotNull UndoableEditor editor) { + undoImpl(ClassUtils.unsafeCast(editor)); + } + + /** + * Revert changes. + * + * @param editor the editor. + */ + @FxThread + protected void undoImpl(@NotNull E editor) { + startInFx(editor); + startUndoInFx(editor); + + ExecutorManager.getInstance() + .addJmeTask(() -> { + startInJme(editor); + undoInJme(editor); + endInJme(editor); + ExecutorManager.getInstance() + .addFxTask(() -> { + endUndoInFx(editor); + endInFx(editor); + }); + }); + } + + /** + * Start reverting changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void startUndoInFx(@NotNull E editor) { + + } + + /** + * Execute reverting in jME thread. + * + * @param editor the editor. + */ + @JmeThread + protected void undoInJme(@NotNull E editor) { + + } + + /** + * Finish reverting changes in Fx thread. + * + * @param editor the editor. + */ + @FxThread + protected void endUndoInFx(@NotNull E editor) { + + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddAppStateOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddAppStateOperation.java new file mode 100644 index 00000000..e8286d64 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddAppStateOperation.java @@ -0,0 +1,64 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a new {@link SceneAppState} to a {@link SceneNode}. + * + * @author JavaSaBr. + */ +public class AddAppStateOperation extends AbstractEditorOperation { + + /** + * The new scene app state. + */ + @NotNull + private final SceneAppState newState; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public AddAppStateOperation(@NotNull SceneAppState newState, @NotNull SceneNode sceneNode) { + this.newState = newState; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneNode.addAppState(newState); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyAddedAppState(newState); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneNode.removeAppState(newState); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyRemovedAppState(newState); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddChildOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddChildOperation.java new file mode 100644 index 00000000..06a48a93 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddChildOperation.java @@ -0,0 +1,86 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.plugin.api.RenderFilterRegistry; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a new {@link Spatial} to a {@link Node}. + * + * @author JavaSaBr + */ +public class AddChildOperation extends AbstractEditorOperation { + + /** + * The new child. + */ + @NotNull + private final Spatial newChild; + + /** + * The parent. + */ + @NotNull + private final Node parent; + + /** + * The flag to select added child. + */ + private final boolean needSelect; + + public AddChildOperation(@NotNull Spatial newChild, @NotNull Node parent) { + this(newChild, parent, true); + } + + public AddChildOperation(@NotNull Spatial newChild, @NotNull Node parent, boolean needSelect) { + this.newChild = newChild; + this.parent = parent; + this.needSelect = needSelect; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + + editor.notifyJmePreChangeProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); + + parent.attachChildAt(newChild, 0); + + editor.notifyJmeChangedProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); + + RenderFilterRegistry.getInstance() + .refreshFilters(); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(parent, newChild, 0, needSelect); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + parent.detachChild(newChild); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(parent, newChild); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddControlOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddControlOperation.java new file mode 100644 index 00000000..f903b91d --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddControlOperation.java @@ -0,0 +1,64 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a control to a node. + * + * @author JavaSaBr + */ +public class AddControlOperation extends AbstractEditorOperation { + + /** + * The new control. + */ + @NotNull + private final Control newControl; + + /** + * The parent. + */ + @NotNull + private final Spatial spatial; + + public AddControlOperation(@NotNull Control newControl, @NotNull Spatial spatial) { + this.newControl = newControl; + this.spatial = spatial; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + spatial.addControl(newControl); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(spatial, newControl, -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + spatial.removeControl(newControl); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(spatial, newControl); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddLightOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddLightOperation.java new file mode 100644 index 00000000..951eeb5b --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddLightOperation.java @@ -0,0 +1,64 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a {@link Light} to a {@link Node}. + * + * @author JavaSaBr + */ +public class AddLightOperation extends AbstractEditorOperation { + + /** + * The new light. + */ + @NotNull + private final Light light; + + /** + * The parent. + */ + @NotNull + private final Node parent; + + public AddLightOperation(@NotNull Light light, @NotNull Node parent) { + this.light = light; + this.parent = parent; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + parent.addLight(light); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(parent, light, -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + parent.removeLight(light); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(parent, light); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddSceneFilterOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddSceneFilterOperation.java new file mode 100644 index 00000000..546ea832 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddSceneFilterOperation.java @@ -0,0 +1,64 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a new {@link SceneFilter} to a {@link SceneNode}. + * + * @author JavaSaBr. + */ +public class AddSceneFilterOperation extends AbstractEditorOperation { + + /** + * The new filter. + */ + @NotNull + private final SceneFilter sceneFilter; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public AddSceneFilterOperation(@NotNull SceneFilter sceneFilter, @NotNull SceneNode sceneNode) { + this.sceneFilter = sceneFilter; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneNode.addFilter(sceneFilter); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyAddedFilter(sceneFilter); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneNode.removeFilter(sceneFilter); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyRemovedFilter(sceneFilter); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/AddVehicleWheelOperation.java b/src/main/java/com/ss/builder/model/undo/impl/AddVehicleWheelOperation.java new file mode 100644 index 00000000..548e1f3d --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/AddVehicleWheelOperation.java @@ -0,0 +1,121 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.rlib.common.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The operation to add a wheel to a vehicle control. + * + * @author JavaSaBr + */ +public class AddVehicleWheelOperation extends AbstractEditorOperation { + + /** + * The vehicle control. + */ + @NotNull + private final VehicleControl control; + + /** + * The connection point. + */ + @NotNull + private final Vector3f connectionPoint; + + /** + * The direction. + */ + @NotNull + private final Vector3f direction; + + /** + * The axle. + */ + @NotNull + private final Vector3f axle; + + /** + * The wheel. + */ + @Nullable + private volatile VehicleWheel createdWheel; + + /** + * The rest length. + */ + private final float restLength; + + /** + * The wheel radius. + */ + private final float wheelRadius; + + /** + * The flag is front wheel. + */ + private final boolean isFrontWheel; + + public AddVehicleWheelOperation( + @NotNull VehicleControl control, + @NotNull Vector3f connectionPoint, + @NotNull Vector3f direction, + @NotNull Vector3f axle, + float restLength, + float wheelRadius, + boolean isFrontWheel + ) { + this.control = control; + this.connectionPoint = connectionPoint; + this.direction = direction; + this.axle = axle; + this.restLength = restLength; + this.wheelRadius = wheelRadius; + this.isFrontWheel = isFrontWheel; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + this.createdWheel = control.addWheel(connectionPoint, direction, axle, restLength, + wheelRadius, isFrontWheel); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(control, ObjectUtils.notNull(createdWheel), -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + + for (int i = 0, length = control.getNumWheels(); i < length; i++) { + if (control.getWheel(i) == createdWheel) { + control.removeWheel(i); + break; + } + } + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(control, ObjectUtils.notNull(createdWheel)); + createdWheel = null; + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/ChangeCollisionShapeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/ChangeCollisionShapeOperation.java new file mode 100644 index 00000000..fbeab2e8 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/ChangeCollisionShapeOperation.java @@ -0,0 +1,89 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The operation to change a collision shape of a model. + * + * @author JavaSaBr + */ +public class ChangeCollisionShapeOperation extends AbstractEditorOperation { + + /** + * The new shape. + */ + @NotNull + private final CollisionShape newShape; + + /** + * The previous shape. + */ + @NotNull + private final CollisionShape oldShape; + + /** + * The collision object. + */ + @NotNull + private final PhysicsCollisionObject collisionObject; + + public ChangeCollisionShapeOperation( + @NotNull CollisionShape newShape, + @NotNull CollisionShape oldShape, + @NotNull PhysicsCollisionObject collisionObject + ) { + this.newShape = newShape; + this.oldShape = oldShape; + this.collisionObject = collisionObject; + } + + @Override + @FxThread + protected void startRedoInFx(@NotNull ModelChangeConsumer editor) { + super.startRedoInFx(editor); + editor.notifyFxRemovedChild(collisionObject, oldShape); + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + collisionObject.setCollisionShape(newShape); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(collisionObject, newShape, -1, true); + } + + @Override + @FxThread + protected void startUndoInFx(@NotNull ModelChangeConsumer editor) { + super.startUndoInFx(editor); + editor.notifyFxRemovedChild(collisionObject, newShape); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + collisionObject.setCollisionShape(oldShape); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(collisionObject, oldShape, -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/ChangeControlsOperation.java b/src/main/java/com/ss/builder/model/undo/impl/ChangeControlsOperation.java new file mode 100644 index 00000000..410184b1 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/ChangeControlsOperation.java @@ -0,0 +1,83 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to chane {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class ChangeControlsOperation extends AbstractEditorOperation { + + /** + * The controls to change. + */ + @NotNull + private final Array controls; + + public ChangeControlsOperation(@NotNull Array controls) { + this.controls = controls; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + controls.forEachR(this, ChangeControlsOperation::redoChange); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + controls.forEachR(this, ChangeControlsOperation::undoChange); + } + + @Override + @FxThread + protected void endInFx(@NotNull ModelChangeConsumer editor) { + super.endInFx(editor); + controls.forEachRm(editor, getPropertyName(), ChangeConsumer::notifyFxChangeProperty); + } + + /** + * Apply new changes to the control. + * + * @param control the control. + */ + @JmeThread + protected void redoChange(@NotNull Control control) { + } + + /** + * Revert changes for the control. + * + * @param control the control. + */ + @JmeThread + protected void undoChange(@NotNull Control control) { + } + + /** + * Get the property name. + * + * @return the property name. + */ + @FromAnyThread + protected @NotNull String getPropertyName() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/ChangeMeshOperation.java b/src/main/java/com/ss/builder/model/undo/impl/ChangeMeshOperation.java new file mode 100644 index 00000000..cf5a599e --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/ChangeMeshOperation.java @@ -0,0 +1,72 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; + +import org.jetbrains.annotations.NotNull; + +/** + * The operation to change a mesh of a model. + * + * @author JavaSaBr + */ +public class ChangeMeshOperation extends AbstractEditorOperation { + + /** + * The new mesh. + */ + @NotNull + private final Mesh newMesh; + + /** + * The previous mesh. + */ + @NotNull + private final Mesh oldMesh; + + /** + * The geometry. + */ + @NotNull + private final Geometry geometry; + + public ChangeMeshOperation(@NotNull Mesh newMesh, @NotNull Mesh oldMesh, @NotNull Geometry geometry) { + this.newMesh = newMesh; + this.oldMesh = oldMesh; + this.geometry = geometry; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + geometry.setMesh(newMesh); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxChangeProperty(geometry, newMesh, "mesh"); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + geometry.setMesh(oldMesh); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxChangeProperty(geometry, oldMesh, "mesh"); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/DisableAppStateOperation.java b/src/main/java/com/ss/builder/model/undo/impl/DisableAppStateOperation.java new file mode 100644 index 00000000..ec6085f9 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/DisableAppStateOperation.java @@ -0,0 +1,56 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to disable a {@link SceneAppState}. + * + * @author JavaSaBr + */ +public class DisableAppStateOperation extends AbstractEditorOperation { + + /** + * The scene app state. + */ + @NotNull + private final SceneAppState appState; + + public DisableAppStateOperation(@NotNull SceneAppState appState) { + this.appState = appState; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + appState.setEnabled(false); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyChangedAppState(appState); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + appState.setEnabled(true); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyChangedAppState(appState); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/DisableControlsOperation.java b/src/main/java/com/ss/builder/model/undo/impl/DisableControlsOperation.java new file mode 100644 index 00000000..fac60496 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/DisableControlsOperation.java @@ -0,0 +1,45 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.ControlUtils; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to disable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class DisableControlsOperation extends ChangeControlsOperation { + + public DisableControlsOperation(@NotNull Array controls) { + super(controls); + } + + @Override + @JmeThread + protected void redoChange(@NotNull Control control) { + super.redoChange(control); + ControlUtils.setEnabled(control, false); + } + + @Override + @JmeThread + protected void undoChange(@NotNull Control control) { + super.undoChange(control); + ControlUtils.setEnabled(control, true); + } + + @Override + @FromAnyThread + protected @NotNull String getPropertyName() { + return Messages.MODEL_PROPERTY_IS_ENABLED; + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/DisableSceneFilterOperation.java b/src/main/java/com/ss/builder/model/undo/impl/DisableSceneFilterOperation.java new file mode 100644 index 00000000..52dffc14 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/DisableSceneFilterOperation.java @@ -0,0 +1,57 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to disable a {@link SceneFilter}. + * + * @author JavaSaBr. + */ +public class DisableSceneFilterOperation extends AbstractEditorOperation { + + /** + * The scene filter. + */ + @NotNull + private final SceneFilter sceneFilter; + + public DisableSceneFilterOperation(@NotNull SceneFilter sceneFilter) { + this.sceneFilter = sceneFilter; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneFilter.setEnabled(false); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyChangedFilter(sceneFilter); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneFilter.setEnabled(true); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyChangedFilter(sceneFilter); + } + +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/EnableAppStateOperation.java b/src/main/java/com/ss/builder/model/undo/impl/EnableAppStateOperation.java new file mode 100644 index 00000000..35b448a3 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/EnableAppStateOperation.java @@ -0,0 +1,56 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to enable a {@link SceneAppState}. + * + * @author JavaSaBr + */ +public class EnableAppStateOperation extends AbstractEditorOperation { + + /** + * The scene app state. + */ + @NotNull + private final SceneAppState appState; + + public EnableAppStateOperation(@NotNull SceneAppState appState) { + this.appState = appState; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + appState.setEnabled(true); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyChangedAppState(appState); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + appState.setEnabled(false); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyChangedAppState(appState); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/EnableControlsOperation.java b/src/main/java/com/ss/builder/model/undo/impl/EnableControlsOperation.java new file mode 100644 index 00000000..e5b373f1 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/EnableControlsOperation.java @@ -0,0 +1,45 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.ControlUtils; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to enable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class EnableControlsOperation extends ChangeControlsOperation { + + public EnableControlsOperation(@NotNull Array controls) { + super(controls); + } + + @Override + @JmeThread + protected void redoChange(@NotNull Control control) { + super.redoChange(control); + ControlUtils.setEnabled(control, true); + } + + @Override + @JmeThread + protected void undoChange(@NotNull Control control) { + super.undoChange(control); + ControlUtils.setEnabled(control, false); + } + + @Override + @FromAnyThread + protected @NotNull String getPropertyName() { + return Messages.MODEL_PROPERTY_IS_ENABLED; + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/EnableSceneFilterOperation.java b/src/main/java/com/ss/builder/model/undo/impl/EnableSceneFilterOperation.java new file mode 100644 index 00000000..b957de01 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/EnableSceneFilterOperation.java @@ -0,0 +1,56 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to enable a {@link SceneFilter}. + * + * @author JavaSaBr + */ +public class EnableSceneFilterOperation extends AbstractEditorOperation { + + /** + * The scene filter. + */ + @NotNull + private final SceneFilter sceneFilter; + + public EnableSceneFilterOperation(@NotNull SceneFilter sceneFilter) { + this.sceneFilter = sceneFilter; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneFilter.setEnabled(true); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyChangedFilter(sceneFilter); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneFilter.setEnabled(false); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyChangedFilter(sceneFilter); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/ModifyingActionOperation.java b/src/main/java/com/ss/builder/model/undo/impl/ModifyingActionOperation.java new file mode 100644 index 00000000..4338c7bd --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/ModifyingActionOperation.java @@ -0,0 +1,72 @@ +package com.ss.builder.model.undo.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.action.ModifyingAction; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.util.JmbEditorEnvoriment; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The implementation of the {@link AbstractEditorOperation} to execute {@link ModifyingAction}. + * + * @author JavaSaBr + */ +public class ModifyingActionOperation extends AbstractEditorOperation { + + /** + * The action. + */ + @NotNull + private final ModifyingAction modifyingAction; + + /** + * The action's owner. + */ + @NotNull + private final Object owner; + + /** + * The prev. state. + */ + @Nullable + private volatile Object state; + + public ModifyingActionOperation(@NotNull ModifyingAction modifyingAction, @NotNull Object owner) { + this.modifyingAction = modifyingAction; + this.owner = owner; + } + + @Override + @JmeThread + protected void endInJme(@NotNull ChangeConsumer editor) { + super.endInJme(editor); + editor.notifyJmeObjectChanged(owner); + } + + @Override + @FxThread + protected void endInFx(@NotNull ChangeConsumer editor) { + super.endInFx(editor); + editor.notifyFxObjectChanged(owner); + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ChangeConsumer editor) { + super.redoInJme(editor); + state = modifyingAction.redo(JmbEditorEnvoriment.getInstance(), owner); + } + + @Override + @FxThread + protected void undoInJme(@NotNull ChangeConsumer editor) { + super.undoInJme(editor); + modifyingAction.undo(JmbEditorEnvoriment.getInstance(), owner, notNull(state)); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/MoveChildOperation.java b/src/main/java/com/ss/builder/model/undo/impl/MoveChildOperation.java new file mode 100644 index 00000000..4dc2af1c --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/MoveChildOperation.java @@ -0,0 +1,84 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; + +import org.jetbrains.annotations.NotNull; + +/** + * The operation to move a node. + * + * @author JavaSaBr + */ +public class MoveChildOperation extends AbstractEditorOperation { + + /** + * The moved node. + */ + @NotNull + private final Spatial moved; + + /** + * The old parent. + */ + @NotNull + private final Node oldParent; + + /** + * The new parent. + */ + @NotNull + private final Node newParent; + + /** + * The child index. + */ + private final int childIndex; + + public MoveChildOperation( + @NotNull Spatial moved, + @NotNull Node oldParent, + @NotNull Node newParent, + int childIndex + ) { + this.moved = moved; + this.oldParent = oldParent; + this.newParent = newParent; + this.childIndex = childIndex; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + newParent.attachChildAt(moved, 0); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxMoved(oldParent, newParent, moved, 0, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + oldParent.attachChildAt(moved, childIndex); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxMoved(newParent, oldParent, moved, childIndex, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/MoveControlOperation.java b/src/main/java/com/ss/builder/model/undo/impl/MoveControlOperation.java new file mode 100644 index 00000000..7ad98307 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/MoveControlOperation.java @@ -0,0 +1,78 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The operation to move a control. + * + * @author JavaSaBr + */ +public class MoveControlOperation extends AbstractEditorOperation { + + /** + * The moved node. + */ + @NotNull + private final Control moved; + + /** + * The old parent. + */ + @NotNull + private Spatial oldParent; + + /** + * The new parent. + */ + @NotNull + private Spatial newParent; + + public MoveControlOperation( + @NotNull Control moved, + @NotNull Spatial oldParent, + @NotNull Spatial newParent + ) { + this.moved = moved; + this.oldParent = oldParent; + this.newParent = newParent; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + oldParent.removeControl(moved); + newParent.addControl(moved); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxMoved(oldParent, newParent, moved, -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + newParent.removeControl(moved); + oldParent.addControl(moved); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxMoved(newParent, oldParent, moved, -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/OptimizeGeometryOperation.java b/src/main/java/com/ss/builder/model/undo/impl/OptimizeGeometryOperation.java new file mode 100644 index 00000000..59063e01 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/OptimizeGeometryOperation.java @@ -0,0 +1,87 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The action to optimize geometry. + * + * @author JavaSaBr + */ +public class OptimizeGeometryOperation extends AbstractEditorOperation { + + /** + * The new element. + */ + @NotNull + private final Spatial newSpatial; + + /** + * The old element. + */ + @NotNull + private final Spatial oldSpatial; + + /** + * The parent node. + */ + @NotNull + private final Node parent; + + public OptimizeGeometryOperation(@NotNull Spatial newSpatial, @NotNull Spatial oldSpatial, @NotNull Node parent) { + this.newSpatial = newSpatial; + this.oldSpatial = oldSpatial; + this.parent = parent; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + apply(oldSpatial, newSpatial); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxReplaced(parent, oldSpatial, newSpatial, true, false); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + apply(newSpatial, oldSpatial); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxReplaced(parent, newSpatial, oldSpatial, true, false); + } + + /** + * Apply changes. + * + * @param newSpatial the new spatial. + * @param oldSpatial the new old spatial. + */ + @JmeThread + private void apply(@NotNull Spatial newSpatial,@NotNull Spatial oldSpatial) { + + var index = parent.getChildIndex(newSpatial); + + parent.detachChildAt(index); + parent.attachChildAt(oldSpatial, index); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveAppStateOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveAppStateOperation.java new file mode 100644 index 00000000..6f88d2f7 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveAppStateOperation.java @@ -0,0 +1,65 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.app.state.SceneAppState; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove a {@link SceneAppState} from a {@link + * SceneNode}*. + * + * @author JavaSaBr. + */ +public class RemoveAppStateOperation extends AbstractEditorOperation { + + /** + * The new scene app state. + */ + @NotNull + private final SceneAppState newState; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public RemoveAppStateOperation(@NotNull SceneAppState newState, @NotNull SceneNode sceneNode) { + this.newState = newState; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneNode.removeAppState(newState); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyRemovedAppState(newState); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneNode.addAppState(newState); + } + + @Override + @JmeThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyAddedAppState(newState); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveChildOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveChildOperation.java new file mode 100644 index 00000000..0d108b38 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveChildOperation.java @@ -0,0 +1,73 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; + +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove {@link Spatial} from the {@link Node}. + * + * @author JavaSaBr. + */ +public class RemoveChildOperation extends AbstractEditorOperation { + + /** + * The child to remove. + */ + @NotNull + private final Spatial child; + + /** + * The parent element. + */ + @NotNull + private final Node parent; + + /** + * The index of position in the parent. + */ + private final int childIndex; + + public RemoveChildOperation(@NotNull Spatial child, @NotNull Node parent) { + this.child = child; + this.parent = parent; + this.childIndex = parent.getChildIndex(child); + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + parent.detachChild(child); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(parent, child); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + parent.attachChildAt(child, childIndex); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(parent, child, childIndex, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveControlOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveControlOperation.java new file mode 100644 index 00000000..91d53616 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveControlOperation.java @@ -0,0 +1,66 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; + +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove a control from a node. + * + * @author JavaSaBr + */ +public class RemoveControlOperation extends AbstractEditorOperation { + + /** + * The control. + */ + @NotNull + private final Control control; + + /** + * The parent. + */ + @NotNull + private final Spatial parent; + + public RemoveControlOperation(@NotNull Control control, @NotNull Spatial parent) { + this.control = control; + this.parent = parent; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + parent.removeControl(control); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(parent, control); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + parent.addControl(control); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(parent, control, -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveElementsOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveElementsOperation.java new file mode 100644 index 00000000..676df970 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveElementsOperation.java @@ -0,0 +1,169 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove elements from a scene. + * + * @author JavaSaBr. + */ +public class RemoveElementsOperation extends AbstractEditorOperation { + + public static class Element { + + /** + * The element to remove. + */ + @NotNull + private final Object element; + + /** + * The element's parent. + */ + @NotNull + private final Object parent; + + /** + * The index of position in the parent. + */ + private int index; + + public Element(@NotNull Object element, @NotNull Object parent) { + this.element = element; + this.parent = parent; + this.index = -1; + } + } + + /** + * The elements to remove. + */ + @NotNull + private final Array elements; + + public RemoveElementsOperation(@NotNull Array elements) { + this.elements = elements; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + + elements.forEach(this, (element, op) -> { + + var toRemove = element.element; + + if (toRemove instanceof Spatial) { + op.removeSpatial(element, (Spatial) toRemove); + } else if (toRemove instanceof Light) { + op.removeLight(element, (Light) toRemove); + } else if (toRemove instanceof Animation) { + op.removeAnimation(element, (Animation) toRemove); + } else if (toRemove instanceof Control) { + op.removeControl(element, (Control) toRemove); + } + }); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + elements.forEach(editor, (element, consumer) -> + consumer.notifyFxRemovedChild(element.parent, element.element)); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + + elements.forEach(this, (element, op) -> { + + var toRemove = element.element; + + if (toRemove instanceof Spatial) { + op.restoreSpatial(element, (Spatial) toRemove); + } else if (toRemove instanceof Light) { + op.restoreLight(element, (Light) toRemove); + } else if (toRemove instanceof Animation) { + op.restoreAnimation(element, (Animation) toRemove); + } else if (toRemove instanceof Control) { + op.restoreControl(element, (Control) toRemove); + } + }); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + elements.forEach(editor, (element, consumer) -> + consumer.notifyFxAddedChild(element.parent, element.element, element.index, false)); + } + + @JmeThread + private void removeSpatial(@NotNull Element element, @NotNull Spatial toRemove) { + var parent = (Node) element.parent; + element.index = parent.getChildIndex(toRemove); + parent.detachChild(toRemove); + } + + @JmeThread + private void restoreSpatial(@NotNull Element element, @NotNull Spatial toRestore) { + var parent = (Node) element.parent; + parent.attachChildAt(toRestore, element.index); + } + + @JmeThread + private void removeControl(@NotNull Element element, @NotNull Control toRemove) { + var parent = (Spatial) element.parent; + parent.removeControl(toRemove); + } + + @JmeThread + private void restoreControl(@NotNull Element element, @NotNull Control toRestore) { + var parent = (Spatial) element.parent; + parent.addControl(toRestore); + } + + @JmeThread + private void removeLight(@NotNull Element element, @NotNull Light toRemove) { + var parent = (Spatial) element.parent; + parent.removeLight(toRemove); + } + + @JmeThread + private void restoreLight(@NotNull Element element, @NotNull Light toRestore) { + var parent = (Spatial) element.parent; + parent.addLight(toRestore); + } + + @JmeThread + private void removeAnimation(@NotNull Element element, @NotNull Animation toRemove) { + var parent = (AnimControl) element.parent; + parent.removeAnim(toRemove); + } + + @JmeThread + private void restoreAnimation(@NotNull Element element, @NotNull Animation toRestore) { + var parent = (AnimControl) element.parent; + parent.addAnim(toRestore); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveLightOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveLightOperation.java new file mode 100644 index 00000000..ab81999d --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveLightOperation.java @@ -0,0 +1,67 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; + +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove a {@link Light} from the {@link Spatial}. + * + * @author JavaSaBr. + */ +public class RemoveLightOperation extends AbstractEditorOperation { + + /** + * The light to remove. + */ + @NotNull + private final Light light; + + /** + * The parent. + */ + @NotNull + private final Node parent; + + public RemoveLightOperation(@NotNull Light light, @NotNull Node parent) { + this.light = light; + this.parent = parent; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + parent.removeLight(light); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(parent, light); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + parent.addLight(light); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(parent, light, -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveSceneFilterOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveSceneFilterOperation.java new file mode 100644 index 00000000..eba82ff7 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveSceneFilterOperation.java @@ -0,0 +1,64 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove a {@link SceneFilter} from a {@link SceneNode}. + * + * @author JavaSaBr. + */ +public class RemoveSceneFilterOperation extends AbstractEditorOperation { + + /** + * The new scene filter. + */ + @NotNull + private final SceneFilter sceneFilter; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public RemoveSceneFilterOperation(@NotNull SceneFilter sceneFilter, @NotNull SceneNode sceneNode) { + this.sceneFilter = sceneFilter; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull SceneChangeConsumer editor) { + super.redoInJme(editor); + sceneNode.removeFilter(sceneFilter); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull SceneChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyRemovedFilter(sceneFilter); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull SceneChangeConsumer editor) { + super.undoInJme(editor); + sceneNode.addFilter(sceneFilter); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull SceneChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyAddedFilter(sceneFilter); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RemoveVehicleWheelOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RemoveVehicleWheelOperation.java new file mode 100644 index 00000000..ec5aee9d --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RemoveVehicleWheelOperation.java @@ -0,0 +1,115 @@ +package com.ss.builder.model.undo.impl; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The operation to remove a wheel from a vehicle control. + * + * @author JavaSaBr + */ +public class RemoveVehicleWheelOperation extends AbstractEditorOperation { + + /** + * The vehicle control. + */ + @NotNull + private final VehicleControl control; + + /** + * The connection point. + */ + @NotNull + private final Vector3f connectionPoint; + + /** + * The direction. + */ + @NotNull + private final Vector3f direction; + + /** + * The axle. + */ + @NotNull + private final Vector3f axle; + + /** + * The wheel. + */ + @Nullable + private volatile VehicleWheel wheel; + + /** + * The rest length. + */ + private final float restLength; + + /** + * The wheel radius. + */ + private final float wheelRadius; + + /** + * The flag is front wheel. + */ + private final boolean isFrontWheel; + + public RemoveVehicleWheelOperation(@NotNull VehicleControl control, @NotNull VehicleWheel wheel) { + this.control = control; + this.connectionPoint = wheel.getLocation(); + this.direction = wheel.getDirection(); + this.axle = wheel.getAxle(); + this.restLength = wheel.getRestLength(); + this.wheelRadius = wheel.getRadius(); + this.isFrontWheel = wheel.isFrontWheel(); + this.wheel = wheel; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + + super.redoInJme(editor); + + for (int i = 0, length = control.getNumWheels(); i < length; i++) { + var wheel = control.getWheel(i); + if (wheel == this.wheel) { + control.removeWheel(i); + break; + } + } + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(control, notNull(wheel)); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + this.wheel = control.addWheel(connectionPoint, direction, axle, restLength, + wheelRadius, isFrontWheel); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(control, notNull(wheel), -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RenameEditableNameOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RenameEditableNameOperation.java new file mode 100644 index 00000000..78c22181 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RenameEditableNameOperation.java @@ -0,0 +1,20 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.editor.extension.EditableName; +import org.jetbrains.annotations.NotNull; + +/** + * The operation to rename an editable name object. + * + * @author JavaSaBr + */ +public class RenameEditableNameOperation extends RenameObjectOperation { + + public RenameEditableNameOperation( + @NotNull String oldName, + @NotNull String newName, + @NotNull EditableName object + ) { + super(oldName, newName, object, EditableName::setName); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RenameLightOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RenameLightOperation.java new file mode 100644 index 00000000..b7a11d02 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RenameLightOperation.java @@ -0,0 +1,16 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.light.Light; +import org.jetbrains.annotations.NotNull; + +/** + * The operation to rename light. + * + * @author JavaSaBr + */ +public class RenameLightOperation extends RenameObjectOperation { + + public RenameLightOperation(@NotNull String oldName, @NotNull String newName, @NotNull Light object) { + super(oldName, newName, object, Light::setName); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RenameNodeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RenameNodeOperation.java new file mode 100644 index 00000000..66d62ede --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RenameNodeOperation.java @@ -0,0 +1,23 @@ +package com.ss.builder.model.undo.impl; + +import com.jme3.scene.Spatial; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiConsumer; + +/** + * The operation to rename a node. + * + * @author JavaSaBr + */ +public class RenameNodeOperation extends RenameObjectOperation { + + public RenameNodeOperation( + @NotNull String oldName, + @NotNull String newName, + @NotNull Spatial object + ) { + super(oldName, newName, object, Spatial::setName); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/RenameObjectOperation.java b/src/main/java/com/ss/builder/model/undo/impl/RenameObjectOperation.java new file mode 100644 index 00000000..3fcf9e67 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/RenameObjectOperation.java @@ -0,0 +1,73 @@ +package com.ss.builder.model.undo.impl; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiConsumer; + +/** + * The operation to rename light. + */ +public abstract class RenameObjectOperation extends AbstractEditorOperation { + + public static final String PROPERTY_NAME = "name"; + + @NotNull + private final BiConsumer<@NotNull T, @NotNull String> nameSetter; + + /** + * The old name. + */ + @NotNull + private final String oldName; + + /** + * The new name. + */ + @NotNull + private final String newName; + + /** + * The object. + */ + @NotNull + private final T object; + + public RenameObjectOperation( + @NotNull String oldName, + @NotNull String newName, + @NotNull T object, + @NotNull BiConsumer<@NotNull T, @NotNull String> nameSetter + ) { + this.oldName = oldName; + this.newName = newName; + this.object = object; + this.nameSetter = nameSetter; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + nameSetter.accept(object, newName); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + nameSetter.accept(object, oldName); + } + + @Override + @FxThread + protected void endInFx(@NotNull ModelChangeConsumer editor) { + super.endInFx(editor); + editor.notifyFxChangeProperty(object, PROPERTY_NAME); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/animation/AddAnimationNodeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/animation/AddAnimationNodeOperation.java new file mode 100644 index 00000000..45bac718 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/animation/AddAnimationNodeOperation.java @@ -0,0 +1,65 @@ +package com.ss.builder.model.undo.impl.animation; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add an animation. + * + * @author JavaSaBr + */ +public class AddAnimationNodeOperation extends AbstractEditorOperation { + + /** + * The animation control. + */ + @NotNull + private final AnimControl control; + + /** + * The animation. + */ + @NotNull + private final Animation animation; + + public AddAnimationNodeOperation(@NotNull Animation animation, @NotNull AnimControl control) { + this.animation = animation; + this.control = control; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + control.addAnim(animation); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(control, animation, -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + control.removeAnim(animation); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(control, animation); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/animation/RemoveAnimationNodeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/animation/RemoveAnimationNodeOperation.java new file mode 100644 index 00000000..0adcd569 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/animation/RemoveAnimationNodeOperation.java @@ -0,0 +1,65 @@ +package com.ss.builder.model.undo.impl.animation; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to delete an animation. + * + * @author JavaSaBr + */ +public class RemoveAnimationNodeOperation extends AbstractEditorOperation { + + /** + * The animation control. + */ + @NotNull + private final AnimControl control; + + /** + * The animation. + */ + @NotNull + private final Animation animation; + + public RemoveAnimationNodeOperation(@NotNull Animation animation, @NotNull AnimControl control) { + this.animation = animation; + this.control = control; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + control.removeAnim(animation); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(control, animation); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + control.addAnim(animation); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(control, animation, -1, false); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/animation/RenameAnimationNodeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/animation/RenameAnimationNodeOperation.java new file mode 100644 index 00000000..eced5362 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/animation/RenameAnimationNodeOperation.java @@ -0,0 +1,77 @@ +package com.ss.builder.model.undo.impl.animation; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.builder.util.AnimationUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} for editing name of an animation. + * + * @author JavaSaBr + */ +public class RenameAnimationNodeOperation extends AbstractEditorOperation { + + /** + * The old name. + */ + @NotNull + private final String oldName; + + /** + * The new name. + */ + @NotNull + private final String newName; + + /** + * The animation control. + */ + @NotNull + private final AnimControl control; + + public RenameAnimationNodeOperation( + @NotNull String oldName, + @NotNull String newName, + @NotNull AnimControl control + ) { + this.oldName = oldName; + this.newName = newName; + this.control = control; + } + + @Override + @JmeThread + protected void redoImpl(@NotNull ModelChangeConsumer editor) { + super.redoImpl(editor); + AnimationUtils.changeName(control, control.getAnim(oldName), oldName, newName); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxChangeProperty(control, control.getAnim(newName), "name"); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + AnimationUtils.changeName(control, control.getAnim(newName), newName, oldName); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxChangeProperty(control, control.getAnim(oldName), "name"); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeEmitterShapeOperation.java b/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeEmitterShapeOperation.java new file mode 100644 index 00000000..148a7fe6 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeEmitterShapeOperation.java @@ -0,0 +1,73 @@ +package com.ss.builder.model.undo.impl.emitter; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.shapes.EmitterShape; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} for changing a shape in the {@link ParticleEmitter}. + * + * @author JavaSaBr. + */ +public class ChangeEmitterShapeOperation extends AbstractEditorOperation { + + /** + * The emitter. + */ + @NotNull + private final ParticleEmitter emitter; + + /** + * The prev shape. + */ + @NotNull + private final EmitterShape prevShape; + + /** + * The new shape. + */ + @NotNull + private final EmitterShape newShape; + + public ChangeEmitterShapeOperation(@NotNull EmitterShape newShape, @NotNull ParticleEmitter emitter) { + this.newShape = newShape; + this.prevShape = emitter.getShape(); + this.emitter = emitter; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + emitter.setShape(newShape); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxReplaced(emitter, prevShape, newShape, true, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + emitter.setShape(prevShape); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxReplaced(emitter, newShape, prevShape, true, true); + } + +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java b/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java new file mode 100644 index 00000000..fd75eb75 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java @@ -0,0 +1,76 @@ +package com.ss.builder.model.undo.impl.emitter; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to change a {@link ParticleInfluencer} to a {@link + * ParticleEmitter}. + * + * @author JavaSaBr. + */ +public class ChangeParticleInfluencerOperation extends AbstractEditorOperation { + + /** + * The particle emitter. + */ + @NotNull + private final ParticleEmitter emitter; + + /** + * The prev influencer. + */ + @NotNull + private final ParticleInfluencer prevInfluencer; + + /** + * The new influencer. + */ + @NotNull + private final ParticleInfluencer newInfluencer; + + public ChangeParticleInfluencerOperation( + @NotNull ParticleInfluencer influencer, + @NotNull ParticleEmitter emitter + ) { + this.prevInfluencer = emitter.getParticleInfluencer(); + this.newInfluencer = influencer; + this.emitter = emitter; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + emitter.setParticleInfluencer(newInfluencer); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxReplaced(emitter, prevInfluencer, newInfluencer, true, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + emitter.setParticleInfluencer(prevInfluencer); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxReplaced(emitter, newInfluencer, prevInfluencer, true, true); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/scene/AddSceneLayerOperation.java b/src/main/java/com/ss/builder/model/undo/impl/scene/AddSceneLayerOperation.java new file mode 100644 index 00000000..71a4d772 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/scene/AddSceneLayerOperation.java @@ -0,0 +1,77 @@ +package com.ss.builder.model.undo.impl.scene; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a layer to a scene. + * + * @author JavaSaBr + */ +public class AddSceneLayerOperation extends AbstractEditorOperation { + + /** + * The layers root. + */ + @NotNull + private final LayersRoot layersRoot; + + /** + * The new layer. + */ + @NotNull + private final SceneLayer layer; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public AddSceneLayerOperation( + @NotNull LayersRoot layersRoot, + @NotNull SceneLayer layer, + @NotNull SceneNode sceneNode + ) { + this.layersRoot = layersRoot; + this.layer = layer; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + sceneNode.addLayer(layer); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxAddedChild(layersRoot, layer, -1, true); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + sceneNode.removeLayer(layer); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxRemovedChild(layersRoot, layer); + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java b/src/main/java/com/ss/builder/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java new file mode 100644 index 00000000..d50e66d9 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java @@ -0,0 +1,70 @@ +package com.ss.builder.model.undo.impl.scene; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.editor.extension.scene.SceneLayer; + +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to add a layer to a scene. + * + * @author JavaSaBr + */ +public class ChangeVisibleSceneLayerOperation extends AbstractEditorOperation { + + /** + * The layer. + */ + @NotNull + private final SceneLayer layer; + + /** + * The flag is need to show. + */ + private volatile boolean needShow; + + public ChangeVisibleSceneLayerOperation(@NotNull SceneLayer layer, boolean needShow) { + this.layer = layer; + this.needShow = needShow; + } + + @Override + @JmeThread + protected void startInJme(@NotNull ModelChangeConsumer editor) { + + super.startInJme(editor); + + var currentModel = editor.getCurrentModel(); + + if (needShow && !layer.isShowed()) { + layer.show(); + currentModel.depthFirstTraversal(this::updateSpatial); + } else if (!needShow && layer.isShowed()) { + layer.hide(); + currentModel.depthFirstTraversal(this::updateSpatial); + } + + needShow = !needShow; + } + + @Override + @FxThread + protected void endInFx(@NotNull ModelChangeConsumer editor) { + super.endInFx(editor); + editor.notifyFxChangeProperty(layer, "Showed"); + } + + @JmeThread + private void updateSpatial(@NotNull Spatial spatial) { + if (SceneLayer.getLayer(spatial) == layer) { + spatial.setVisible(layer.isShowed()); + } + } +} diff --git a/src/main/java/com/ss/builder/model/undo/impl/scene/RemoveSceneLayerOperation.java b/src/main/java/com/ss/builder/model/undo/impl/scene/RemoveSceneLayerOperation.java new file mode 100644 index 00000000..fa998d46 --- /dev/null +++ b/src/main/java/com/ss/builder/model/undo/impl/scene/RemoveSceneLayerOperation.java @@ -0,0 +1,109 @@ +package com.ss.builder.model.undo.impl.scene; + +import com.jme3.scene.Spatial; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.model.undo.editor.ModelChangeConsumer; +import com.ss.builder.model.undo.impl.AbstractEditorOperation; +import com.ss.builder.model.node.layer.LayersRoot; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.editor.extension.scene.SceneNode; + +import org.jetbrains.annotations.NotNull; + +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove a layer from a scene. + * + * @author JavaSaBr + */ +public class RemoveSceneLayerOperation extends AbstractEditorOperation { + + /** + * The list with spatials which uses this layer. + */ + @NotNull + private final Array toRevert; + + /** + * The layer layersRoot. + */ + @NotNull + private final LayersRoot layersRoot; + + /** + * The removed layer. + */ + @NotNull + private final SceneLayer layer; + + /** + * The scene node. + */ + @NotNull + private final SceneNode sceneNode; + + public RemoveSceneLayerOperation( + @NotNull LayersRoot layersRoot, + @NotNull SceneLayer layer, + @NotNull SceneNode sceneNode + ) { + + this.toRevert = Array.ofType(Spatial.class); + this.layersRoot = layersRoot; + this.layer = layer; + this.sceneNode = sceneNode; + } + + @Override + @JmeThread + protected void redoInJme(@NotNull ModelChangeConsumer editor) { + super.redoInJme(editor); + + var currentModel = editor.getCurrentModel(); + currentModel.depthFirstTraversal(this::clean); + + sceneNode.removeLayer(layer); + } + + @Override + @FxThread + protected void endRedoInFx(@NotNull ModelChangeConsumer editor) { + super.endRedoInFx(editor); + editor.notifyFxRemovedChild(layersRoot, layer); + } + + @Override + @JmeThread + protected void undoInJme(@NotNull ModelChangeConsumer editor) { + super.undoInJme(editor); + + sceneNode.addLayer(layer); + + toRevert.forEach(spatial -> SceneLayer.setLayer(layer, spatial)); + toRevert.forEach(spatial -> spatial.setVisible(layer.isShowed())); + toRevert.clear(); + } + + @Override + @FxThread + protected void endUndoInFx(@NotNull ModelChangeConsumer editor) { + super.endUndoInFx(editor); + editor.notifyFxAddedChild(layersRoot, layer, -1, false); + } + + @JmeThread + private void clean(@NotNull Spatial spatial) { + var currentLayer = SceneLayer.getLayer(spatial); + if (currentLayer == layer) { + toRevert.add(spatial); + SceneLayer.setLayer(null, spatial); + spatial.setVisible(true); + } + } +} diff --git a/src/main/java/com/ss/editor/model/workspace/Workspace.java b/src/main/java/com/ss/builder/model/workspace/Workspace.java similarity index 85% rename from src/main/java/com/ss/editor/model/workspace/Workspace.java rename to src/main/java/com/ss/builder/model/workspace/Workspace.java index 5ee77603..3a6a5169 100644 --- a/src/main/java/com/ss/editor/model/workspace/Workspace.java +++ b/src/main/java/com/ss/builder/model/workspace/Workspace.java @@ -1,15 +1,14 @@ -package com.ss.editor.model.workspace; +package com.ss.builder.model.workspace; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; +import static com.ss.builder.util.EditorUtils.getAssetFile; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.WorkspaceManager; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.editor.EditorDescriptor; +import com.ss.builder.editor.FileEditor; +import com.ss.builder.editor.state.EditorState; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.util.StringUtils; @@ -130,8 +129,8 @@ public synchronized void updateCurrentEditedFile(@Nullable final Path file) { return; } - final Path assetFile = getAssetFile(getAssetFolder(), file); - this.currentEditedFile = toAssetPath(assetFile); + final Path assetFile = EditorUtils.getAssetFile(getAssetFolder(), file); + this.currentEditedFile = EditorUtils.toAssetPath(assetFile); } /** @@ -197,18 +196,24 @@ public synchronized void updateExpandedFolders(@NotNull final Array folder * @return the state of the editor. */ @FromAnyThread - public synchronized @NotNull T getEditorState(@NotNull final Path file, - @NotNull final Supplier stateFactory) { + public synchronized @NotNull T getEditorState( + @NotNull Path file, + @NotNull Supplier stateFactory + ) { - final Path assetFile = getAssetFile(getAssetFolder(), file); - final String assetPath = toAssetPath(assetFile); + var assetPath = EditorUtils.getAssetFileOpt(file) + .map(EditorUtils::toAssetPath) + .orElseThrow(() -> new RuntimeException("The file " + file + " isn't in the current asset folder.")); - final Map editorStateMap = getEditorStateMap(); + var editorStateMap = getEditorStateMap(); if (!editorStateMap.containsKey(assetPath)) { - final EditorState editorState = stateFactory.get(); + + var editorState = stateFactory.get(); editorState.setChangeHandler(this::incrementChanges); + editorStateMap.put(assetPath, editorState); + incrementChanges(); } @@ -223,8 +228,8 @@ public synchronized void updateExpandedFolders(@NotNull final Array folder @FromAnyThread public synchronized void removeEditorState(@NotNull final Path file) { - final Path assetFile = getAssetFile(getAssetFolder(), file); - final String assetPath = toAssetPath(assetFile); + final Path assetFile = EditorUtils.getAssetFile(getAssetFolder(), file); + final String assetPath = EditorUtils.toAssetPath(assetFile); final Map editorStateMap = getEditorStateMap(); if (editorStateMap.remove(assetPath) == null) return; @@ -261,10 +266,10 @@ public synchronized void setAssetFolder(@NotNull final Path assetFolder) { @FromAnyThread public synchronized void addOpenedFile(@NotNull final Path file, @NotNull final FileEditor fileEditor) { - final Path assetFile = getAssetFile(getAssetFolder(), file); - final String assetPath = toAssetPath(assetFile); + final Path assetFile = EditorUtils.getAssetFile(getAssetFolder(), file); + final String assetPath = EditorUtils.toAssetPath(assetFile); - final EditorDescription description = fileEditor.getDescription(); + final EditorDescriptor description = fileEditor.getDescriptor(); final Map openedFiles = getOpenedFiles(); final String previous = openedFiles.put(assetPath, description.getEditorId()); @@ -283,8 +288,8 @@ public synchronized void addOpenedFile(@NotNull final Path file, @NotNull final @FromAnyThread public synchronized void removeOpenedFile(@NotNull final Path file) { - final Path assetFile = getAssetFile(getAssetFolder(), file); - final String assetPath = toAssetPath(assetFile); + final Path assetFile = EditorUtils.getAssetFile(getAssetFolder(), file); + final String assetPath = EditorUtils.toAssetPath(assetFile); final Map openedFiles = getOpenedFiles(); openedFiles.remove(assetPath); @@ -364,7 +369,7 @@ public synchronized void save(final boolean force) { changes.set(0); try { - Files.write(workspaceFile, EditorUtil.serialize(this)); + Files.write(workspaceFile, EditorUtils.serialize(this)); } catch (final IOException e) { LOGGER.warning(e); } diff --git a/src/main/java/com/ss/builder/plugin/EditorPlugin.java b/src/main/java/com/ss/builder/plugin/EditorPlugin.java new file mode 100644 index 00000000..a3872bab --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/EditorPlugin.java @@ -0,0 +1,116 @@ +package com.ss.builder.plugin; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.fx.css.CssRegistry; +import com.ss.builder.manager.ResourceManager; +import com.ss.rlib.common.plugin.PluginContainer; +import com.ss.rlib.common.plugin.PluginSystem; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.plugin.impl.BasePlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URL; + +/** + * The base implementation of a plugin for this editor. + * + * @author JavaSaBr + */ +public class EditorPlugin extends BasePlugin { + + public EditorPlugin(@NotNull PluginContainer pluginContainer) { + super(pluginContainer); + } + + /** + * Register this plugin's specific resources in the manager. + * + * @param resourceManager the resource manager. + */ + @BackgroundThread + public void register(@NotNull ResourceManager resourceManager) { + } + + /** + * Register this plugin's own CSS files. + * + * @param registry the CSS registry. + */ + @BackgroundThread + public void register(@NotNull CssRegistry registry) { + } + + /** + * Register all necessary extensions. + * + * @param manager the extension point's manager. + */ + @BackgroundThread + public void register(@NotNull ExtensionPointManager manager) { + } + + /** + * Do some things after when jME context was created. + * + * @param pluginSystem the plugin system. + */ + @BackgroundThread + public void onAfterCreateJmeContext(@NotNull PluginSystem pluginSystem) { + } + + /** + * Do some things after when JavaFX context was created. + * + * @param pluginSystem the plugin system. + */ + @BackgroundThread + public void onAfterCreateJavaFxContext(@NotNull PluginSystem pluginSystem) { + } + + /** + * Do some things before when the editor is ready to work. + * + * @param pluginSystem the plugin system. + */ + @BackgroundThread + public void onFinishLoading(@NotNull PluginSystem pluginSystem) { + } + + @Override + @FromAnyThread + public @NotNull PluginContainer getContainer() { + return super.getContainer(); + } + + /** + * Get the URL to a home page of this plugin. + * + * @return the URL of a home page of this plugin or null. + */ + @FromAnyThread + public @Nullable URL getHomePageUrl() { + return null; + } + + /** + * Get the HTML presentation of plugin's dependencies as gradle dependencies. + * + * @return the HTML presentation of plugin's dependencies as gradle dependencies. + */ + @FromAnyThread + public @Nullable String getUsedGradleDependencies() { + return null; + } + + /** + * Get the HTML presentation of plugin's dependencies as maven dependencies. + * + * @return the HTML presentation of plugin's dependencies as maven dependencies. + */ + @FromAnyThread + public @Nullable String getUsedMavenDependencies() { + return null; + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/RenderFilterRegistry.java b/src/main/java/com/ss/builder/plugin/api/RenderFilterRegistry.java new file mode 100644 index 00000000..da7de2b6 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/RenderFilterRegistry.java @@ -0,0 +1,103 @@ +package com.ss.builder.plugin.api; + +import com.jme3.post.Filter; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.AsyncEventManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.event.impl.AllPluginsExtensionsRegisteredEvent; +import com.ss.builder.fx.event.impl.JmeContextCreatedEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.manager.AsyncEventManager.CombinedAsyncEventHandlerBuilder; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.event.impl.AllPluginsExtensionsRegisteredEvent; +import com.ss.builder.fx.event.impl.JmeContextCreatedEvent; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import org.jetbrains.annotations.NotNull; + +/** + * The registry of some additional render filters. + * + * @author JavaSaBr + */ +public class RenderFilterRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(RenderFilterRegistry.class); + + public interface FilterExtension { + + @FromAnyThread + @NotNull Filter getFilter(); + + @JmeThread + default void refresh() { + } + } + + /** + * @see FilterExtension + */ + public static final String EP_FILTERS = "RenderFilterExtension#filters"; + + private static final ExtensionPoint EXTENSIONS = + ExtensionPointManager.register(EP_FILTERS); + + private static final RenderFilterRegistry INSTANCE = new RenderFilterRegistry(); + + @FromAnyThread + public static @NotNull RenderFilterRegistry getInstance() { + return INSTANCE; + } + + private RenderFilterRegistry() { + + AsyncEventManager.CombinedAsyncEventHandlerBuilder.of(this::applyExtensions) + .add(AllPluginsExtensionsRegisteredEvent.EVENT_TYPE) + .add(JmeContextCreatedEvent.EVENT_TYPE) + .buildAndRegister(); + + LOGGER.info("initialized."); + } + + @BackgroundThread + private void applyExtensions() { + ExecutorManager.getInstance() + .addJmeTask(this::applyExtensionsInJme); + } + + @BackgroundThread + private void applyExtensionsInJme() { + + var postProcessor = EditorUtils.getGlobalFilterPostProcessor(); + + for (var extension : EXTENSIONS) { + postProcessor.addFilter(extension.getFilter()); + } + + LOGGER.info("applied additional filter extensions."); + } + + /** + * Refresh all filters. + */ + @JmeThread + public void refreshFilters() { + EXTENSIONS.forEach(FilterExtension::refresh); + } + + @JmeThread + public void enableFilters() { + } + + @JmeThread + public void disableFilters() { + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java b/src/main/java/com/ss/builder/plugin/api/dialog/GenericFactoryDialog.java similarity index 75% rename from src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java rename to src/main/java/com/ss/builder/plugin/api/dialog/GenericFactoryDialog.java index 3b8959af..ef418908 100644 --- a/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java +++ b/src/main/java/com/ss/builder/plugin/api/dialog/GenericFactoryDialog.java @@ -1,15 +1,23 @@ -package com.ss.editor.plugin.api.dialog; +package com.ss.builder.plugin.api.dialog; -import static com.ss.editor.plugin.api.property.control.PropertyEditorControlFactory.build; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.plugin.api.property.control.PropertyEditorControl; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxUtils; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,6 +85,12 @@ public GenericFactoryDialog( this.validator = validator; this.vars = VarTable.newInstance(); this.validateCallback = this::validate; + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); createControls(); validate(); } @@ -139,14 +153,13 @@ protected void createContent(@NotNull VBox root) { */ @FxThread private void createControls() { + getDefinitions().forEach(getRoot(), (definition, root) -> { - var children = getRoot().getChildren(); + var control = PropertyEditorControlFactory.build(vars, definition, validateCallback); + control.prefWidthProperty() + .bind(widthProperty()); - var definitions = getDefinitions(); - definitions.forEach(definition -> { - var control = build(vars, definition, validateCallback); - control.prefWidthProperty().bind(widthProperty()); - children.add(control); + FxUtils.addChild(root, control); }); } diff --git a/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditor.java b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditor.java new file mode 100644 index 00000000..b3a02317 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditor.java @@ -0,0 +1,27 @@ +package com.ss.builder.plugin.api.editor; + +import static com.ss.builder.editor.FileEditorUtils.loadCameraState; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.editor.part3d.Advanced3dFileEditor3dEditorPart; +import com.ss.builder.editor.state.impl.Editor3dEditorState; + +/** + * The advanced implementation of 3D editor. + * + * @author JavaSaBr + */ +public abstract class Advanced3dFileEditor + extends Base3dFileEditor { + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + var editorState = getEditorState(); + + if (editorState != null) { + loadCameraState(editorState, editor3dPart); + } + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithRightTool.java b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithRightTool.java new file mode 100644 index 00000000..62af4760 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithRightTool.java @@ -0,0 +1,179 @@ +package com.ss.builder.plugin.api.editor; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.editor.part3d.Advanced3dFileEditor3dEditorPart; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.editor.state.impl.Editor3dWithEditorToolEditorState; +import com.ss.builder.fx.component.split.pane.EditorToolSplitPane; +import com.ss.builder.fx.component.tab.EditorToolComponent; +import com.ss.builder.fx.component.tab.ScrollableEditorToolComponent; +import com.ss.rlib.fx.util.FxUtils; +import javafx.event.Event; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The advanced implementation of 3D editor with a right tool. + * + * @author JavaSaBr + */ +public abstract class Advanced3dFileEditorWithRightTool + extends Advanced3dFileEditor { + + /** + * The pane of editor area. + */ + @NotNull + protected final StackPane editorAreaPane; + + /** + * The pane of 3D editor area. + */ + @NotNull + private final BorderPane editor3dArea; + + /** + * The main split container. + */ + @Nullable + private EditorToolSplitPane mainSplitContainer; + + /** + * Editor tool component. + */ + @Nullable + private ScrollableEditorToolComponent editorToolComponent; + + protected Advanced3dFileEditorWithRightTool() { + this.editorAreaPane = new StackPane(); + this.editor3dArea = new BorderPane(); + } + + @Override + @FxThread + protected void createContent(@NotNull StackPane root) { + createEditorAreaPane(); + + mainSplitContainer = new EditorToolSplitPane(EditorUtils.getFxScene(), root); + + editorToolComponent = new ScrollableEditorToolComponent(mainSplitContainer, 1); + editorToolComponent.prefHeightProperty().bind(root.heightProperty()); + + createToolComponents(editorToolComponent, root); + + editorToolComponent.addChangeListener((observable, oldValue, newValue) -> processChangeTool(oldValue, newValue)); + editorToolComponent.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { + var editorState = getEditorState(); + if (editorState != null) { + editorState.setOpenedTool(newValue.intValue()); + } + }); + + mainSplitContainer.initFor(editorToolComponent, editorAreaPane); + + FxUtils.addClass(mainSplitContainer, CssClasses.FILE_EDITOR_MAIN_SPLIT_PANE); + FxUtils.addChild(root, mainSplitContainer); + } + + /** + * Create editor area pane. + */ + @FxThread + protected void createEditorAreaPane() { + + editorAreaPane.setOnDragOver(this::handleDragOverEvent); + editorAreaPane.setOnDragDropped(this::handleDragDroppedEvent); + + editor3dArea.setOnMousePressed(event -> editor3dArea.requestFocus()); + editor3dArea.setOnKeyReleased(Event::consume); + editor3dArea.setOnKeyPressed(Event::consume); + + FxUtils.addClass(editorAreaPane, CssClasses.FILE_EDITOR_EDITOR_AREA); + FxUtils.addChild(editorAreaPane, editor3dArea); + } + + /** + * Process change tool. + * + * @param oldValue the old value + * @param newValue the new value + */ + @FxThread + protected void processChangeTool(@Nullable Number oldValue, @NotNull Number newValue) { + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + var editorState = getEditorState(); + if (editorState == null) { + return; + } + + getEditorToolComponent().getSelectionModel() + .select(editorState.getOpenedTool()); + + getMainSplitContainer().updateFor(editorState); + } + + @Override + @FxThread + public @NotNull BorderPane get3dArea() { + return editor3dArea; + } + + /** + * Get the editor tool component. + * + * @return the editor tool component. + */ + @FxThread + protected @NotNull ScrollableEditorToolComponent getEditorToolComponent() { + return notNull(editorToolComponent); + } + + /** + * Get the main split container. + * + * @return the main split container. + */ + @FxThread + protected @NotNull EditorToolSplitPane getMainSplitContainer() { + return notNull(mainSplitContainer); + } + + /** + * Create and add tool components to the container. + * + * @param container the tool container. + * @param root the root. + */ + @FxThread + protected void createToolComponents(@NotNull EditorToolComponent container, @NotNull StackPane root) { + } + + /** + * Handle drag over events. + * + * @param dragEvent the drag event. + */ + @FxThread + protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { + } + + /** + * Handle dropped events. + * + * @param dragEvent the drop event. + */ + @FxThread + protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithSplitRightTool.java b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithSplitRightTool.java new file mode 100644 index 00000000..93804edd --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/Advanced3dFileEditorWithSplitRightTool.java @@ -0,0 +1,56 @@ +package com.ss.builder.plugin.api.editor; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.editor.part3d.Advanced3dFileEditor3dEditorPart; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.editor.state.impl.Editor3dWithEditorToolEditorState; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.Node; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; + +/** + * The advanced implementation of 3D editor with a split right tool. + * + * @author JavaSaBr + */ +public abstract class Advanced3dFileEditorWithSplitRightTool extends + Advanced3dFileEditorWithRightTool { + + /** + * Build split component. + * + * @param first the first component. + * @param second the second component. + * @param root the root. + * @return the result component. + */ + @FxThread + protected Region buildSplitComponent(@NotNull Node first, @NotNull Node second, @NotNull StackPane root) { + + var splitPane = new SplitPane(first, second); + splitPane.prefHeightProperty() + .bind(root.heightProperty()); + splitPane.prefWidthProperty() + .bind(root.widthProperty()); + + root.heightProperty() + .addListener((observableValue, oldValue, newValue) -> calcVSplitSize(splitPane)); + + FxUtils.addClass(splitPane, CssClasses.FILE_EDITOR_TOOL_SPLIT_PANE); + + return splitPane; + } + + /** + * Calc height of vertical split pane. + * + * @param splitPane the split pane + */ + @FxThread + protected void calcVSplitSize(@NotNull SplitPane splitPane) { + splitPane.setDividerPosition(0, 0.3); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/Base3dFileEditor.java b/src/main/java/com/ss/builder/plugin/api/editor/Base3dFileEditor.java new file mode 100644 index 00000000..97a3a17d --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/Base3dFileEditor.java @@ -0,0 +1,91 @@ +package com.ss.builder.plugin.api.editor; + +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.jme.editor.part3d.impl.AbstractEditor3dPart; +import com.ss.builder.editor.state.impl.Editor3dEditorState; +import javafx.event.Event; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.ScrollEvent; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +/** + * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor} with 3D scene. + * + * @author JavaSaBr + */ +public abstract class Base3dFileEditor extends + BaseFileEditor { + + /** + * The 3D part of this editor. + */ + @NotNull + protected final T editor3dPart; + + public Base3dFileEditor() { + this.editor3dPart = create3dEditorPart(); + addEditor3dPart(editor3dPart); + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + super.openFile(file); + } + + @Override + protected boolean needListenEventsFromPage() { + return false; + } + + /** + * Create 3D part of this editor. + * + * @return the 3D part. + */ + @FxThread + protected abstract @NotNull T create3dEditorPart(); + + @Override + @FxThread + public void notifyChangedCameraSettings( + @NotNull Vector3f cameraLocation, + float hRotation, + float vRotation, + float targetDistance, + float cameraSpeed + ) { + + super.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed); + + var state = getEditorState(); + + if (state != null) { + state.setCameraHRotation(hRotation); + state.setCameraVRotation(vRotation); + state.setCameraTargetDistance(targetDistance); + state.setCameraLocation(cameraLocation); + state.setCameraFlySpeed(cameraSpeed); + } + } + + @Override + @FxThread + public boolean isInside(double sceneX, double sceneY, @NotNull Class eventType) { + + var editorPage = getUiPage(); + var editor3dPage = get3dArea() == null ? editorPage : get3dArea(); + + var only3D = eventType.isAssignableFrom(MouseEvent.class) || + eventType.isAssignableFrom(ScrollEvent.class); + + var page = only3D ? editor3dPage : editorPage; + var point2d = page.sceneToLocal(sceneX, sceneY); + + return page.contains(point2d); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditor.java b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditor.java new file mode 100644 index 00000000..0082aa7e --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditor.java @@ -0,0 +1,240 @@ +package com.ss.builder.plugin.api.editor; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.WorkspaceManager; +import com.ss.builder.editor.event.FileEditorEvent; +import com.ss.builder.model.undo.EditorOperation; +import com.ss.builder.model.undo.EditorOperationControl; +import com.ss.builder.model.undo.UndoableEditor; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.editor.impl.AbstractFileEditorLegacy; +import com.ss.builder.editor.state.EditorState; +import javafx.event.Event; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +/** + * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor}. + * + * @author JavaSaBr + */ +public abstract class BaseFileEditor extends AbstractFileEditorLegacy implements + UndoableEditor, ChangeConsumer { + + /** + * The operation control. + */ + @NotNull + protected final EditorOperationControl operationControl; + + /** + * The changes counter. + */ + @NotNull + private final AtomicInteger changeCounter; + + /** + * The state of this editor. + */ + @Nullable + protected S editorState; + + /** + * The flag for ignoring listeners. + */ + private boolean ignoreListeners; + + protected BaseFileEditor() { + this.operationControl = createOperationControl(); + this.changeCounter = new AtomicInteger(); + } + + /** + * Create an editor operation control. + * + * @return the editor operation control. + */ + @FxThread + protected @NotNull EditorOperationControl createOperationControl() { + return new EditorOperationControl(this); + } + + @Override + @FromAnyThread + public void execute(@NotNull final EditorOperation operation) { + operationControl.execute(operation); + } + + @FxThread + @Override + protected boolean handleKeyActionInFx( + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + + if (isPressed && isControlDown && keyCode == KeyCode.Z) { + undo(); + return true; + } else if (isPressed && isControlDown && isShiftDown && keyCode == KeyCode.Z) { + redo(); + return true; + } else if (isPressed && isControlDown && keyCode == KeyCode.Y) { + redo(); + return true; + } + + return super.handleKeyActionInFx(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); + } + + @Override + @FxThread + public void notify(@NotNull FileEditorEvent event) { + super.notify(event); + + S editorState = getEditorState(); + + if (editorState != null) { + editorState.notify(event); + } + } + + @Override + @FxThread + public void incrementChange() { + var result = changeCounter.incrementAndGet(); + setDirty(result != 0); + } + + @Override + @FxThread + public void decrementChange() { + var result = changeCounter.decrementAndGet(); + setDirty(result != 0); + } + + @Override + @FromAnyThread + public void redo() { + operationControl.redo(); + } + + @Override + @FromAnyThread + public void undo() { + operationControl.undo(); + } + + @Override + @BackgroundThread + public void openFile(@NotNull Path file) { + super.openFile(file); + + try { + doOpenFile(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + + ExecutorManager.getInstance() + .addFxTask(this::loadState); + } + + /** + * Loading a state of this editor. + */ + @FxThread + protected void loadState() { + + var stateFactory = getEditorStateFactory(); + + if (stateFactory == null) { + return; + } + + editorState = WorkspaceManager.getInstance() + .requiredCurrentWorkspace() + .getEditorState(getFile(), stateFactory); + } + + /** + * Get the factory to make an editor state. + * + * @return the factory to make an editor state. + */ + @FxThread + protected @Nullable Supplier getEditorStateFactory() { + return null; + } + + /** + * Do main activities to open the file. + * + * @param file the file to open. + * @throws IOException if was some problem with writing to the file. + */ + @BackgroundThread + protected void doOpenFile(@NotNull Path file) throws IOException { + } + + /** + * Set true if need to ignore listeners. + * + * @param ignoreListeners true if need to ignore listeners. + */ + @FromAnyThread + protected void setIgnoreListeners(boolean ignoreListeners) { + this.ignoreListeners = ignoreListeners; + } + + /** + * Return true if need to ignore listeners. + * + * @return true if need to ignore listeners. + */ + @FromAnyThread + protected boolean isIgnoreListeners() { + return ignoreListeners; + } + + @Override + @FxThread + protected @NotNull StackPane createRoot() { + return new StackPane(); + } + + @Override + @FxThread + public @Nullable BorderPane get3dArea() { + return null; + } + + /** + * Get the editor state. + * + * @return the editor state. + */ + @FromAnyThread + protected @Nullable S getEditorState() { + return editorState; + } + + @Override + @FxThread + public boolean isInside(double sceneX, double sceneY, @NotNull Class eventType) { + return false; + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithRightTool.java b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithRightTool.java new file mode 100644 index 00000000..486dc480 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithRightTool.java @@ -0,0 +1,134 @@ +package com.ss.builder.plugin.api.editor; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.editor.state.impl.EditorWithEditorToolEditorState; +import com.ss.builder.fx.component.split.pane.EditorToolSplitPane; +import com.ss.builder.fx.component.tab.EditorToolComponent; +import com.ss.builder.fx.component.tab.ScrollableEditorToolComponent; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The base implementation of a file editor without 3D part and with right tool panel. + * + * @author JavaSaBr + */ +public abstract class BaseFileEditorWithRightTool extends BaseFileEditor { + + /** + * The pane of editor area. + */ + @NotNull + private final StackPane editorAreaPane; + + /** + * The main split container. + */ + @Nullable + private EditorToolSplitPane mainSplitContainer; + + /** + * Editor tool component. + */ + @Nullable + private ScrollableEditorToolComponent editorToolComponent; + + protected BaseFileEditorWithRightTool() { + editorAreaPane = new StackPane(); + } + + @Override + @FxThread + protected void createContent(@NotNull StackPane root) { + createEditorAreaPane(); + + mainSplitContainer = new EditorToolSplitPane(EditorUtils.getFxScene(), root); + + editorToolComponent = new ScrollableEditorToolComponent(mainSplitContainer, 1); + editorToolComponent.prefHeightProperty().bind(root.heightProperty()); + + createToolComponents(editorToolComponent, root); + + editorToolComponent.addChangeListener((observable, oldValue, newValue) -> processChangeTool(oldValue, newValue)); + editorToolComponent.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { + var editorState = getEditorState(); + if (editorState != null) { + editorState.setOpenedTool(newValue.intValue()); + } + }); + + mainSplitContainer.initFor(editorToolComponent, editorAreaPane); + + FxUtils.addClass(mainSplitContainer, CssClasses.FILE_EDITOR_MAIN_SPLIT_PANE); + FxUtils.addChild(root, mainSplitContainer); + } + + /** + * Create editor area pane. + */ + @FxThread + protected void createEditorAreaPane() { + + editorAreaPane.setOnDragOver(this::handleDragOverEvent); + editorAreaPane.setOnDragDropped(this::handleDragDroppedEvent); + + FxUtils.addClass(editorAreaPane, CssClasses.FILE_EDITOR_EDITOR_AREA); + } + + /** + * Process change tool. + * + * @param oldValue the old value + * @param newValue the new value + */ + @FxThread + protected void processChangeTool(@Nullable Number oldValue, @NotNull Number newValue) { + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + var editorState = getEditorState(); + if (editorState == null) { + return; + } + + editorToolComponent.getSelectionModel().select(editorState.getOpenedTool()); + mainSplitContainer.updateFor(editorState); + } + + /** + * Create and add tool components to the container. + * + * @param container the tool container. + * @param root the root. + */ + @FxThread + protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { + } + + /** + * Handle drag over events. + * + * @param dragEvent the drag event. + */ + @FxThread + protected void handleDragOverEvent(@NotNull final DragEvent dragEvent) { + } + + /** + * Handle dropped events. + * + * @param dragEvent the drop event. + */ + @FxThread + protected void handleDragDroppedEvent(@NotNull final DragEvent dragEvent) { + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithSplitRightTool.java b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithSplitRightTool.java new file mode 100644 index 00000000..5ada33c7 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithSplitRightTool.java @@ -0,0 +1,55 @@ +package com.ss.builder.plugin.api.editor; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.editor.state.impl.EditorWithEditorToolEditorState; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.Node; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; + +/** + * The base implementation of a file editor without 3D part and with right split tool panel. + * + * @author JavaSaBr + */ +public abstract class BaseFileEditorWithSplitRightTool extends + BaseFileEditorWithRightTool { + + /** + * Build split component. + * + * @param first the first component. + * @param second the second component. + * @param root the root. + * @return the result component. + */ + @FxThread + protected Region buildSplitComponent(@NotNull Node first, @NotNull Node second, @NotNull StackPane root) { + + var splitPane = new SplitPane(first, second); + splitPane.prefHeightProperty() + .bind(root.heightProperty()); + splitPane.prefWidthProperty() + .bind(root.widthProperty()); + + root.heightProperty() + .addListener((observableValue, oldValue, newValue) -> calcVSplitSize(splitPane)); + + FxUtils.addClass(splitPane, CssClasses.FILE_EDITOR_TOOL_SPLIT_PANE); + + return splitPane; + } + + /** + * Calc height of vertical split pane. + * + * @param splitPane the split pane + */ + @FxThread + protected void calcVSplitSize(@NotNull SplitPane splitPane) { + splitPane.setDividerPosition(0, 0.3); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithoutState.java b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithoutState.java new file mode 100644 index 00000000..8aaa04df --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/BaseFileEditorWithoutState.java @@ -0,0 +1,12 @@ +package com.ss.builder.plugin.api.editor; + +import com.ss.builder.editor.state.impl.VoidEditorState; + +/** + * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor} without + * {@link com.ss.editor.ui.component.editor.state.EditorState}. + * + * @author JavaSaBr + */ +public abstract class BaseFileEditorWithoutState extends BaseFileEditor { +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditor3dPart.java b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditor3dPart.java new file mode 100644 index 00000000..6e128cf3 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditor3dPart.java @@ -0,0 +1,266 @@ +package com.ss.builder.plugin.api.editor.material; + +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.asset.AssetNotFoundException; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RendererException; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.ss.builder.EditorThread; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.jme.editor.part3d.control.impl.CameraEditor3dPartControl; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.plugin.api.editor.part3d.AdvancedPbrWithStudioSky3dEditorPart; +import com.ss.builder.editor.impl.material.MaterialFileEditor; +import com.ss.builder.util.TangentGenerator; +import com.ss.rlib.common.geom.util.AngleUtils; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +/** + * The implementation the 3D part of the {@link MaterialFileEditor}. + * + * @author JavaSaBr + */ +public class BaseMaterialEditor3dPart extends + AdvancedPbrWithStudioSky3dEditorPart { + + private static final Vector3f QUAD_OFFSET = + new Vector3f(0, -2, 2); + + private static final Vector3f LIGHT_DIRECTION = + new Vector3f(0.007654993F, 0.39636374F, 0.9180617F).negate(); + + private static final float H_ROTATION = AngleUtils.degreeToRadians(75); + private static final float V_ROTATION = AngleUtils.degreeToRadians(25); + + /** + * The array of all used geometries. + */ + @NotNull + private final Array geometries; + + /** + * The test box. + */ + @NotNull + private final Geometry testBox; + + /** + * The test sphere. + */ + @NotNull + private final Geometry testSphere; + + /** + * The test quad. + */ + @NotNull + private final Geometry testQuad; + + /** + * The current model mode. + */ + @NotNull + private ModelType currentModelType; + + public BaseMaterialEditor3dPart(@NotNull T fileEditor) { + super(fileEditor); + this.testBox = new Geometry("Box", new Box(2, 2, 2)); + this.testSphere = new Geometry("Sphere", new Sphere(30, 30, 2)); + this.testQuad = new Geometry("Quad", new Quad(4, 4)); + this.testQuad.setLocalTranslation(QUAD_OFFSET); + this.geometries = Array.of(testBox, testQuad, testSphere); + this.currentModelType = ModelType.BOX; + + geometries.forEach(TangentGenerator::useMikktspaceGenerator); + + var cameraControl = requireControl(CameraEditor3dPartControl.class); + cameraControl.setLightDirection(LIGHT_DIRECTION); + cameraControl.setDefaultHorizontalRotation(H_ROTATION); + cameraControl.setDefaultVerticalRotation(V_ROTATION); + + controls.add(new BaseMaterialEditorHotKeys3dPartControl(this)); + } + + @Override + @BackgroundThread + protected @NotNull Optional createCameraControl() { + return Optional.of(new CameraEditor3dPartControl(this, false, false, false)); + } + + /** + * Update the {@link Material}. + * + * @param material the material + */ + @FromAnyThread + public void updateMaterial(@NotNull Material material) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateMaterialInJme(material)); + } + + /** + * Update the {@link Material} in the jME thread. + * + * @param material the new material. + */ + @JmeThread + protected void updateMaterialInJme(@NotNull Material material) { + + geometries.forEach(material, Geometry::setMaterial); + + var renderManager = EditorUtils.getRenderManager(); + try { + renderManager.preloadScene(testBox); + } catch (RendererException | AssetNotFoundException | UnsupportedOperationException e) { + handleMaterialException(e); + geometries.forEach(EditorUtils.getDefaultMaterial(), Geometry::setMaterial); + } + } + + /** + * Handle the material exception. + * + * @param exception the exception. + */ + @JmeThread + protected void handleMaterialException(@NotNull RuntimeException exception) { + EditorUtils.handleException(LOGGER, this, exception); + } + + /** + * Change the {@link ModelType}. + * + * @param modelType the model type + */ + @FromAnyThread + public void changeModelType(@NotNull ModelType modelType) { + ExecutorManager.getInstance() + .addJmeTask(() -> changeModeInJme(modelType)); + } + + /** + * Change the {@link ModelType} in the jMe thread. + * + * @param modelType the new model type. + */ + @JmeThread + protected void changeModeInJme(@NotNull ModelType modelType) { + + modelNode.detachAllChildren(); + + switch (modelType) { + case BOX: { + modelNode.attachChild(testBox); + break; + } + case QUAD: { + modelNode.attachChild(testQuad); + break; + } + case SPHERE: { + modelNode.attachChild(testSphere); + break; + } + } + + this.currentModelType = modelType; + } + + /** + * Change the {@link Bucket}. + * + * @param bucket the bucket + */ + @FromAnyThread + public void changeBucketType(@NotNull Bucket bucket) { + ExecutorManager.getInstance() + .addJmeTask(() -> changeBucketTypeInJme(bucket)); + } + + /** + * Change the {@link Bucket} in the jMe thread. + * + * @param bucket the new bucket. + */ + @JmeThread + protected void changeBucketTypeInJme(@NotNull Bucket bucket) { + geometries.forEach(bucket, Geometry::setQueueBucket); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + changeModeInJme(currentModelType); + } + + /** + * Update the light in the scene. + * + * @param enabled the enabled + */ + @FromAnyThread + public void updateLightEnabled(boolean enabled) { + ExecutorManager.getInstance() + .addJmeTask(() -> updateLightEnabledInJme(enabled)); + } + + /** + * Update the light in the scene in the {@link EditorThread}. + * + * @param enabled true if light should be enabled. + */ + @JmeThread + protected void updateLightEnabledInJme(boolean enabled) { + + var cameraControl = requireControl(CameraEditor3dPartControl.class); + + if (enabled) { + cameraControl.enableLight(); + } else { + cameraControl.disableLight(); + } + } + + /** + * The enum Model type. + */ + public enum ModelType { + /** + * Sphere model type. + */ + SPHERE, + /** + * Box model type. + */ + BOX, + /** + * Quad model type. + */ + QUAD; + + private static final ModelType[] VALUES = values(); + + /** + * Value of model type. + * + * @param index the index + * @return the model type + */ + public static ModelType valueOf(int index) { + return VALUES[index]; + } + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditorHotKeys3dPartControl.java b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditorHotKeys3dPartControl.java new file mode 100644 index 00000000..7ebb038c --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialEditorHotKeys3dPartControl.java @@ -0,0 +1,43 @@ +package com.ss.builder.plugin.api.editor.material; + +import com.jme3.input.KeyInput; +import com.jme3.input.controls.KeyTrigger; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.impl.KeyEventRedirectEditor3dPartControl; +import com.ss.builder.jme.editor.part3d.ExtendableEditor3dPart; +import com.ss.builder.jme.editor.part3d.control.impl.KeyEventRedirectEditor3dPartControl; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * The input control of {@link BaseMaterialEditor3dPart} + * + * @author JavaSaBr + */ +public class BaseMaterialEditorHotKeys3dPartControl extends KeyEventRedirectEditor3dPartControl { + + private static final String KEY_C = "jMB.baseMaterialEditorHotKeys.C"; + private static final String KEY_S = "jMB.baseMaterialEditorHotKeys.S"; + private static final String KEY_P = "jMB.baseMaterialEditorHotKeys.P"; + private static final String KEY_L = "jMB.baseMaterialEditorHotKeys.L"; + + private static final ObjectDictionary TRIGGERS = + ObjectDictionary.ofType(String.class, KeyTrigger.class); + + private static final String[] MAPPINGS; + + static { + + TRIGGERS.put(KEY_C, new KeyTrigger(KeyInput.KEY_C)); + TRIGGERS.put(KEY_S, new KeyTrigger(KeyInput.KEY_S)); + TRIGGERS.put(KEY_P, new KeyTrigger(KeyInput.KEY_P)); + TRIGGERS.put(KEY_L, new KeyTrigger(KeyInput.KEY_L)); + + MAPPINGS = TRIGGERS.keyArray(String.class) + .toArray(String.class); + } + + protected BaseMaterialEditorHotKeys3dPartControl(@NotNull ExtendableEditor3dPart editor3dPart) { + super(editor3dPart, TRIGGERS, MAPPINGS); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialFileEditor.java b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialFileEditor.java new file mode 100644 index 00000000..8c4d4a19 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/material/BaseMaterialFileEditor.java @@ -0,0 +1,368 @@ +package com.ss.builder.plugin.api.editor.material; + +import static com.jme3.renderer.queue.RenderQueue.Bucket.Inherit; +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.jme3.material.Material; +import com.jme3.renderer.queue.RenderQueue; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.plugin.api.editor.Advanced3dFileEditorWithSplitRightTool; +import com.ss.builder.plugin.api.editor.material.BaseMaterialEditor3dPart.ModelType; +import com.ss.builder.editor.state.EditorState; +import com.ss.builder.editor.state.impl.EditorMaterialEditorState; +import com.ss.builder.fx.component.tab.EditorToolComponent; +import com.ss.builder.fx.control.property.PropertyEditor; +import com.ss.builder.fx.control.tree.NodeTree; +import com.ss.builder.fx.control.tree.node.TreeNode; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.fx.util.FxUtils; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.scene.control.*; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * The implementation of the Editor to edit materials. + * + * @author JavaSaBr + */ +public abstract class BaseMaterialFileEditor extends + Advanced3dFileEditorWithSplitRightTool { + + /** + * The default state of editor light. + */ + public static final boolean DEFAULT_LIGHT_ENABLED = true; + + /** + * The list of available bucket types. + */ + protected static final ObservableList BUCKETS = + FXCollections.observableArrayList(RenderQueue.Bucket.values()); + + /** + * The settings tree. + */ + @NotNull + protected final NodeTree settingsTree; + + /** + * The property editor. + */ + @NotNull + private final PropertyEditor propertyEditor; + + /** + * The button to use a cube. + */ + @NotNull + private final ToggleButton cubeButton; + + /** + * The button to use a sphere. + */ + @NotNull + private final ToggleButton sphereButton; + + /** + * The button to use a plane. + */ + @NotNull + private final ToggleButton planeButton; + + /** + * The button to use a light. + */ + @NotNull + private final ToggleButton lightButton; + + /** + * The list of RenderQueue.Bucket. + */ + @NotNull + private final ComboBox bucketComboBox; + + protected BaseMaterialFileEditor() { + super(); + this.bucketComboBox = new ComboBox<>(BUCKETS); + this.cubeButton = new ToggleButton(); + this.sphereButton = new ToggleButton(); + this.planeButton = new ToggleButton(); + this.lightButton = new ToggleButton(); + this.settingsTree = new NodeTree<>(this::selectFromTree, getChangeConsumer(), SelectionMode.SINGLE); + this.propertyEditor = new PropertyEditor<>(getChangeConsumer()); + } + + /** + * Get the change consumer. + * + * @return the change consumer. + */ + @FromAnyThread + protected C getChangeConsumer() { + return unsafeCast(this); + } + + @Override + @FxThread + protected boolean handleKeyActionInFx( + @NotNull KeyCode keyCode, + boolean isPressed, + boolean isControlDown, + boolean isShiftDown, + boolean isButtonMiddleDown + ) { + + if (isPressed && keyCode == KeyCode.C && !isControlDown && !isButtonMiddleDown) { + cubeButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.S && !isControlDown && !isButtonMiddleDown) { + sphereButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.P && !isControlDown && !isButtonMiddleDown) { + planeButton.setSelected(true); + return true; + } else if (isPressed && keyCode == KeyCode.L && !isControlDown && !isButtonMiddleDown) { + lightButton.setSelected(!lightButton.isSelected()); + return true; + } + + return super.handleKeyActionInFx(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); + } + + @Override + @FxThread + protected void createToolComponents(@NotNull EditorToolComponent container, @NotNull StackPane root) { + super.createToolComponents(container, root); + + propertyEditor.prefHeightProperty() + .bind(root.heightProperty()); + + container.addComponent(buildSplitComponent(settingsTree, propertyEditor, root), + getSettingsTreeToolName()); + + FxUtils.addClass(settingsTree.getTreeView(), CssClasses.TRANSPARENT_TREE_VIEW); + } + + /** + * Get the settings tree tool name. + * + * @return the settings tree tool name. + */ + @FromAnyThread + protected @NotNull String getSettingsTreeToolName() { + return Messages.MATERIAL_SETTINGS_MAIN; + } + + /** + * Handle selected objects from tree. + * + * @param objects the selected objects. + */ + @FxThread + private void selectFromTree(@NotNull Array objects) { + + Object object = objects.first(); + + Object parent = null; + Object element; + + if (object instanceof TreeNode) { + var treeNode = (TreeNode) object; + var parentNode = treeNode.getParent(); + parent = parentNode == null ? null : parentNode.getElement(); + element = treeNode.getElement(); + } else { + element = object; + } + + propertyEditor.buildFor(element, parent); + } + + @Override + @FxThread + protected void loadState() { + super.loadState(); + + switch (ModelType.valueOf(editorState.getModelType())) { + case BOX: + cubeButton.setSelected(true); + break; + case SPHERE: + sphereButton.setSelected(true); + break; + case QUAD: + planeButton.setSelected(true); + break; + } + + bucketComboBox.getSelectionModel().select(editorState.getBucketType()); + lightButton.setSelected(editorState.isLightEnable()); + } + + @Override + @FxThread + protected @Nullable Supplier getEditorStateFactory() { + return EditorMaterialEditorState::new; + } + + @Override + @FxThread + protected void calcVSplitSize(@NotNull SplitPane splitPane) { + splitPane.setDividerPosition(0, 0.2); + } + + @Override + @FxThread + protected boolean needToolbar() { + return true; + } + + @Override + @FxThread + protected void createToolbar(@NotNull HBox container) { + super.createToolbar(container); + + createActions(container); + + var bucketLabel = new Label(Messages.MATERIAL_FILE_EDITOR_BUCKET_TYPE_LABEL + ":"); + + bucketComboBox.getSelectionModel().select(Inherit); + bucketComboBox.getSelectionModel() + .selectedItemProperty() + .addListener((observable, oldValue, newValue) -> changeBucketType(newValue)); + + FxUtils.addChild(container, bucketLabel, bucketComboBox); + } + + /** + * Create actions on toolbar. + * + * @param container the container. + */ + @FxThread + protected void createActions(@NotNull HBox container) { + + cubeButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_CUBE + " (C)")); + cubeButton.setGraphic(new ImageView(Icons.CUBE_16)); + cubeButton.selectedProperty().addListener((observable, oldValue, newValue) -> + changeModelType(ModelType.BOX, newValue)); + + sphereButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_SPHERE + " (S)")); + sphereButton.setGraphic(new ImageView(Icons.SPHERE_16)); + sphereButton.selectedProperty().addListener((observable, oldValue, newValue) -> + changeModelType(ModelType.SPHERE, newValue)); + + planeButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_PLANE + " (P)")); + planeButton.setGraphic(new ImageView(Icons.PLANE_16)); + planeButton.selectedProperty().addListener((observable, oldValue, newValue) -> + changeModelType(ModelType.QUAD, newValue)); + + lightButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_LIGHT + " (L)")); + lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); + lightButton.setSelected(DEFAULT_LIGHT_ENABLED); + lightButton.selectedProperty().addListener((observable, oldValue, newValue) -> changeLight(newValue)); + + FxUtils.addClass(cubeButton, sphereButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON) + .addClass(planeButton, lightButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); + + FxUtils.addChild(container, createSaveAction(), cubeButton, sphereButton, planeButton, lightButton); + + DynamicIconSupport.addSupport(cubeButton, sphereButton, planeButton, lightButton); + } + + /** + * Handle changing the bucket type. + */ + @FxThread + private void changeBucketType(@NotNull RenderQueue.Bucket newValue) { + + editor3dPart.changeBucketType(newValue); + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setBucketType(newValue); + } + } + + /** + * Handle changing the light enabling. + */ + @FxThread + private void changeLight(@NotNull Boolean newValue) { + + editor3dPart.updateLightEnabled(newValue); + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setLightEnable(newValue); + } + } + + /** + * Handle the changed model type. + */ + @FxThread + private void changeModelType(@NotNull ModelType modelType, @NotNull Boolean newValue) { + + if (newValue == Boolean.FALSE) { + return; + } + + if (modelType == ModelType.BOX) { + cubeButton.setMouseTransparent(true); + sphereButton.setMouseTransparent(false); + planeButton.setMouseTransparent(false); + cubeButton.setSelected(true); + sphereButton.setSelected(false); + planeButton.setSelected(false); + editor3dPart.changeModelType(modelType); + } else if (modelType == ModelType.SPHERE) { + cubeButton.setMouseTransparent(false); + sphereButton.setMouseTransparent(true); + planeButton.setMouseTransparent(false); + cubeButton.setSelected(false); + sphereButton.setSelected(true); + planeButton.setSelected(false); + editor3dPart.changeModelType(modelType); + } else if (modelType == ModelType.QUAD) { + cubeButton.setMouseTransparent(false); + sphereButton.setMouseTransparent(false); + planeButton.setMouseTransparent(true); + sphereButton.setSelected(false); + cubeButton.setSelected(false); + planeButton.setSelected(true); + editor3dPart.changeModelType(modelType); + } + + var editorState = getEditorState(); + + if (editorState != null) { + editorState.setModelType(modelType); + } + } + + @Override + @FxThread + public void notifyFxChangeProperty(@NotNull Object object, @NotNull String propertyName) { + if (object instanceof Material) { + propertyEditor.refresh(); + } else { + propertyEditor.syncFor(object); + } + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/part3d/Advanced3dFileEditor3dEditorPart.java b/src/main/java/com/ss/builder/plugin/api/editor/part3d/Advanced3dFileEditor3dEditorPart.java new file mode 100644 index 00000000..00c6d3f5 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/part3d/Advanced3dFileEditor3dEditorPart.java @@ -0,0 +1,17 @@ +package com.ss.builder.plugin.api.editor.part3d; + +import com.ss.builder.jme.editor.part3d.impl.Base3dSceneEditor3dPart; +import com.ss.builder.plugin.api.editor.Advanced3dFileEditor; +import org.jetbrains.annotations.NotNull; + +/** + * The advanced implementation of 3D part of an editor. + * + * @author JavaSaBr + */ +public abstract class Advanced3dFileEditor3dEditorPart extends Base3dSceneEditor3dPart { + + public Advanced3dFileEditor3dEditorPart(@NotNull T fileEditor) { + super(fileEditor); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbr3dEditorPart.java b/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbr3dEditorPart.java new file mode 100644 index 00000000..854ac7f0 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbr3dEditorPart.java @@ -0,0 +1,83 @@ +package com.ss.builder.plugin.api.editor.part3d; + +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.light.LightProbe; +import com.jme3.scene.Node; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.plugin.api.editor.Advanced3dFileEditor; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The advanced implementation of 3D part of an editor with PBR Light probe. + * + * @author JavaSaBr + */ +public abstract class AdvancedPbr3dEditorPart extends + Advanced3dFileEditor3dEditorPart { + + @NotNull + private final JobProgressAdapter probeHandler = new JobProgressAdapter<>() { + + @Override + public void done(@NotNull LightProbe result) { + if (!isInitialized()) return; + attachModelNode(); + } + }; + + /** + * The model node. + */ + @NotNull + protected final Node modelNode; + + /** + * The count of frames. + */ + private int frame; + + public AdvancedPbr3dEditorPart(@NotNull T fileEditor) { + super(fileEditor); + this.modelNode = new Node("ModelNode"); + } + + @Override + @JmeThread + public void initialize(@NotNull AppStateManager stateManager, @NotNull Application application) { + super.initialize(stateManager, application); + frame = 0; + } + + @Override + @JmeThread + public void cleanup() { + super.cleanup(); + modelNode.detachAllChildren(); + stateNode.detachChild(modelNode); + } + + /** + * Attach model node to state node. + */ + @JmeThread + private void attachModelNode() { + stateNode.attachChild(modelNode); + } + + @Override + @JmeThread + public void update(float tpf) { + super.update(tpf); + + if (frame == 2) { + EditorUtils.updateGlobalLightProbe(probeHandler); + } + + frame++; + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3dEditorPart.java b/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3dEditorPart.java new file mode 100644 index 00000000..57d6cc96 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3dEditorPart.java @@ -0,0 +1,26 @@ +package com.ss.builder.plugin.api.editor.part3d; + +import com.jme3.scene.Geometry; +import com.jme3.util.SkyFactory; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.plugin.api.editor.Advanced3dFileEditor; +import com.ss.builder.util.EditorUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The advanced implementation of 3D part of an editor with PBR Light probe and Studio Sky. + * + * @author JavaSaBr + */ +public class AdvancedPbrWithStudioSky3dEditorPart extends AdvancedPbr3dEditorPart { + + public AdvancedPbrWithStudioSky3dEditorPart(@NotNull T fileEditor) { + super(fileEditor); + + var assetManager = EditorUtils.getAssetManager(); + var sky = (Geometry) SkyFactory.createSky(assetManager, "graphics/textures/sky/studio.hdr", + SkyFactory.EnvMapType.EquirectMap); + + stateNode.attachChild(sky); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/editor/part3d/Base3dEditorPart.java b/src/main/java/com/ss/builder/plugin/api/editor/part3d/Base3dEditorPart.java new file mode 100644 index 00000000..9056fe1c --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/editor/part3d/Base3dEditorPart.java @@ -0,0 +1,12 @@ +package com.ss.builder.plugin.api.editor.part3d; + +import com.ss.builder.jme.editor.part3d.impl.AbstractEditor3dPart; + +/** + * The base implementation of 3D part of an editor. + * + * @author JavaSaBr + */ +public class Base3dEditorPart extends AbstractEditor3dPart { + +} diff --git a/src/main/java/com/ss/builder/plugin/api/file/creator/GenericFileCreator.java b/src/main/java/com/ss/builder/plugin/api/file/creator/GenericFileCreator.java new file mode 100644 index 00000000..90f43c43 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/file/creator/GenericFileCreator.java @@ -0,0 +1,145 @@ +package com.ss.builder.plugin.api.file.creator; + +import static com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory.build; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.plugin.api.property.control.PropertyEditorControlFactory; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.control.PropertyEditorControl; +import com.ss.builder.fx.component.creator.impl.AbstractFileCreator; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import javafx.scene.layout.GridPane; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * The generic implementation of file creator dialog. + * + * @author JavaSaBr + */ +public class GenericFileCreator extends AbstractFileCreator { + + /** + * The result vars of the creator. + */ + @NotNull + protected final VarTable vars; + + /** + * The settings container. + */ + @Nullable + private GridPane settingsContainer; + + public GenericFileCreator() { + this.vars = VarTable.newInstance(); + } + + @Override + protected void createSettings(@NotNull GridPane root) { + super.createSettings(root); + + this.settingsContainer = root; + + var rowIndex = 1; + + for (var definition : getPropertyDefinitions()) { + + var control = PropertyEditorControlFactory.build(vars, definition, this::validateFileName); + control.prefWidthProperty() + .bind(widthProperty()); + + root.add(control, 0, rowIndex++, 2, 1); + } + } + + @Override + @FxThread + public void show(@NotNull Window owner) { + super.show(owner); + validateFileName(); + } + + /** + * Get the settings container. + * + * @return the settings container. + */ + @FxThread + private @NotNull GridPane getSettingsContainer() { + return notNull(settingsContainer); + } + + @Override + @FxThread + protected void validateFileName() { + super.validateFileName(); + + getSettingsContainer().getChildren() + .stream() + .filter(PropertyEditorControl.class::isInstance) + .map(PropertyEditorControl.class::cast) + .forEach(PropertyEditorControl::checkDependency); + + var okButton = getOkButton(); + if (okButton == null) { + return; + } + + var result = validate(vars); + + if (!okButton.isDisabled()) { + okButton.setDisable(!result); + } + } + + /** + * Validate variables. + * + * @param vars the variables. + * @return true if the all variables are valid. + */ + @FxThread + protected boolean validate(@NotNull VarTable vars) { + return true; + } + + @Override + @BackgroundThread + protected void writeData(@NotNull Path resultFile) throws IOException { + writeData(vars, resultFile); + } + + /** + * Write created data to the created file. + * + * @param vars the available variables. + * @param resultFile the result file. + * @throws IOException if was some problem with writing to the result file. + */ + @BackgroundThread + protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { + } + + /** + * Get the list of property definitions. + * + * @return the list of property definitions. + */ + @FromAnyThread + protected @NotNull Array getPropertyDefinitions() { + return Array.empty(); + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/messages/MessagesPluginFactory.java b/src/main/java/com/ss/builder/plugin/api/messages/MessagesPluginFactory.java similarity index 89% rename from src/main/java/com/ss/editor/plugin/api/messages/MessagesPluginFactory.java rename to src/main/java/com/ss/builder/plugin/api/messages/MessagesPluginFactory.java index 5be7faa2..ee640097 100644 --- a/src/main/java/com/ss/editor/plugin/api/messages/MessagesPluginFactory.java +++ b/src/main/java/com/ss/builder/plugin/api/messages/MessagesPluginFactory.java @@ -1,10 +1,12 @@ -package com.ss.editor.plugin.api.messages; +package com.ss.builder.plugin.api.messages; import static java.util.Collections.emptyEnumeration; import static java.util.ResourceBundle.getBundle; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.plugin.EditorPlugin; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.plugin.EditorPlugin; import com.ss.rlib.common.util.PropertyLoader; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/plugin/api/property/PropertyDefinition.java b/src/main/java/com/ss/builder/plugin/api/property/PropertyDefinition.java similarity index 92% rename from src/main/java/com/ss/editor/plugin/api/property/PropertyDefinition.java rename to src/main/java/com/ss/builder/plugin/api/property/PropertyDefinition.java index 5dc57ef3..2cc88bd7 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/PropertyDefinition.java +++ b/src/main/java/com/ss/builder/plugin/api/property/PropertyDefinition.java @@ -1,7 +1,9 @@ -package com.ss.editor.plugin.api.property; +package com.ss.builder.plugin.api.property; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.EditablePropertyType; +import com.ss.rlib.common.util.ObjectUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; @@ -173,15 +175,25 @@ public PropertyDefinition( } /** - * Get the name of the property. + * Get the default value of the property. * - * @return the name of the property. + * @return the default value of the property or null. */ @FromAnyThread public @Nullable Object getDefaultValue() { return defaultValue; } + /** + * Get the default value of the property. + * + * @return the default value of the property. + */ + @FromAnyThread + public @NotNull Object requireDefaultValue() { + return ObjectUtils.notNull(defaultValue); + } + /** * Get the dependencies. * diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/AssetResourcePropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/AssetResourcePropertyEditorControl.java new file mode 100644 index 00000000..cf0ab265 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/AssetResourcePropertyEditorControl.java @@ -0,0 +1,69 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The control to edit resource values from asset. + * + * @author JavaSaBr + */ +public abstract class AssetResourcePropertyEditorControl extends ResourcePropertyEditorControl { + + protected AssetResourcePropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + /** + * Get the action tester for asset dialog. + * + * @return the action tester. + */ + @FromAnyThread + protected @NotNull Predicate> getActionTester() { + return type -> false; + } + + /** + * Get a list with available extensions. + * + * @return the list with available extensions. + */ + @FromAnyThread + protected @NotNull Array getExtensions() { + return Array.empty(); + } + + @Override + @FxThread + protected void chooseNewResource() { + super.chooseNewResource(); + UiUtils.openFileAssetDialog(this::chooseNewResource, getExtensions(), getActionTester()); + } + + /** + * Choose the new resource by the file. + * + * @param file the selected file. + */ + @FxThread + protected void chooseNewResource(@NotNull Path file) { + changed(); + reload(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/AwtFontPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/AwtFontPropertyEditorControl.java new file mode 100644 index 00000000..a5e8fcbf --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/AwtFontPropertyEditorControl.java @@ -0,0 +1,125 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.AwtFontSuggestionProvider; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.AwtFontSuggestionProvider; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import impl.org.controlsfx.autocompletion.AutoCompletionTextFieldBinding; +import javafx.scene.control.ComboBox; +import javafx.util.StringConverter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.Arrays; + +/** + * The control to choose string value from list. + * + * @author JavaSaBr + */ +public class AwtFontPropertyEditorControl extends PropertyEditorControl { + + private static final GraphicsEnvironment GRAPHICS_ENVIRONMENT = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + + private static final Font[] FONTS = + GRAPHICS_ENVIRONMENT.getAllFonts(); + + private static final StringConverter STRING_CONVERTER = new StringConverter<>() { + + @Override + public @NotNull String toString(@Nullable Font font) { + return font == null ? StringUtils.EMPTY : font.getFontName(); + } + + @Override + public @Nullable Font fromString(@NotNull String fontName) { + return Arrays.stream(FONTS) + .filter(font -> font.getFontName().equals(fontName)) + .findAny().orElse(null); + } + }; + + /** + * The list of available options of the string value. + */ + @NotNull + private final ComboBox comboBox; + + protected AwtFontPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.comboBox = new ComboBox<>(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + comboBox.getItems().addAll(FONTS); + comboBox.setVisibleRowCount(20); + comboBox.setConverter(STRING_CONVERTER); + comboBox.setEditable(true); + comboBox.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + var selectionModel = comboBox.getSelectionModel(); + var editor = comboBox.getEditor(); + + var binding = new AutoCompletionTextFieldBinding(editor, + new AwtFontSuggestionProvider(comboBox.getItems()), STRING_CONVERTER); + + binding.setOnAutoCompleted(event -> selectionModel.select(event.getCompletion())); + binding.prefWidthProperty() + .bind(comboBox.widthProperty().multiply(1.3)); + + FxControlUtils.onSelectedItemChange(comboBox, newValue -> { + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> editor.positionCaret(newValue.getFontName().length())); + }); + + FxControlUtils.onSelectedItemChange(comboBox, this::changed); + + FxUtils.addClass(editor, + CssClasses.TRANSPARENT_TEXT_FIELD, CssClasses.TEXT_FIELD_IN_COMBO_BOX) + .addClass(comboBox, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(this, comboBox); + } + + @Override + @FxThread + protected void reloadImpl() { + + comboBox.getSelectionModel() + .select(getPropertyValue()); + + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + + setPropertyValue(comboBox + .getSelectionModel() + .getSelectedItem()); + + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/BooleanPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/BooleanPropertyEditorControl.java new file mode 100644 index 00000000..6def62ab --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/BooleanPropertyEditorControl.java @@ -0,0 +1,63 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.CheckBox; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit boolean values. + * + * @author JavaSaBr + */ +public class BooleanPropertyEditorControl extends PropertyEditorControl { + + /** + * The {@link CheckBox} with current value. + */ + @NotNull + private final CheckBox checkBox; + + protected BooleanPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.checkBox = new CheckBox(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + checkBox.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onSelectedChange(checkBox, this::changed); + + FxUtils.addClass(checkBox, CssClasses.PROPERTY_CONTROL_CHECK_BOX); + FxUtils.addChild(this, checkBox); + } + + @Override + @FxThread + protected void reloadImpl() { + checkBox.setSelected(Boolean.TRUE.equals(getPropertyValue())); + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + setPropertyValue(checkBox.isSelected()); + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/ClasspathResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ClasspathResourcePropertyControl.java new file mode 100644 index 00000000..310dd4c5 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ClasspathResourcePropertyControl.java @@ -0,0 +1,86 @@ +package com.ss.builder.plugin.api.property.control; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit resource values from classpath. + * + * @author JavaSaBr + */ +public class ClasspathResourcePropertyControl extends ResourcePropertyEditorControl { + + /** + * The target extension. + */ + @NotNull + private final String extension; + + public ClasspathResourcePropertyControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.extension = notNull(definition.getExtension()); + } + + @Override + @FxThread + protected void chooseNewResource() { + super.chooseNewResource(); + + var resources = ResourceManager.getInstance() + .getAvailableResources(extension); + + UiUtils.openResourceAssetDialog(this::chooseNewResource, this::validate, resources); + } + + /** + * Choose the new resource by the path + * + * @param resource the selected resource. + */ + @FxThread + private void chooseNewResource(@NotNull String resource) { + setPropertyValue(resource); + changed(); + reload(); + } + + /** + * Validate the selected resource. + * + * @param resource the selected resource. + * @return the message of problems or null if all are ok. + */ + @FxThread + private String validate(@NotNull String resource) { + + var extension = FileUtils.getExtension(resource); + + if (StringUtils.isEmpty(extension)) { + return Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE; + } + + return null; + } + + @Override + @FxThread + protected void reloadImpl() { + resourceLabel.setText(StringUtils.ifEmpty(getPropertyValue(), NOT_SELECTED)); + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/ColorPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ColorPropertyEditorControl.java new file mode 100644 index 00000000..0475551c --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ColorPropertyEditorControl.java @@ -0,0 +1,67 @@ +package com.ss.builder.plugin.api.property.control; + +import com.jme3.math.ColorRGBA; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ColorPicker; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit color values. + * + * @author JavaSaBr + */ +public class ColorPropertyEditorControl extends PropertyEditorControl { + + /** + * The color picker. + */ + @NotNull + private final ColorPicker colorPicker; + + protected ColorPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.colorPicker = new ColorPicker(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + colorPicker.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onColorChange(colorPicker, this::changed); + + FxUtils.addClass(colorPicker, + CssClasses.PROPERTY_CONTROL_COLOR_PICKER); + + FxUtils.addChild(this, colorPicker); + } + + @Override + protected void reloadImpl() { + colorPicker.setValue(UiUtils.from(getPropertyValue())); + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + setPropertyValue(UiUtils.from(colorPicker.getValue())); + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/ComboBoxPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ComboBoxPropertyEditorControl.java new file mode 100644 index 00000000..451747fb --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ComboBoxPropertyEditorControl.java @@ -0,0 +1,72 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.ComboBox; +import org.jetbrains.annotations.NotNull; + +/** + * The combo box based property control. + * + * @author JavaSaBr + */ +public class ComboBoxPropertyEditorControl extends PropertyEditorControl { + + /** + * The list of available options. + */ + @NotNull + protected final ComboBox comboBox; + + protected ComboBoxPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.comboBox = new ComboBox<>(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + comboBox.setVisibleRowCount(20); + comboBox.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onSelectedItemChange(comboBox, this::changed); + + FxUtils.addClass(comboBox, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(this, comboBox); + } + + @Override + @FxThread + protected void reloadImpl() { + + comboBox.getSelectionModel() + .select(getPropertyValue()); + + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + + setPropertyValue(comboBox.getSelectionModel() + .getSelectedItem()); + + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/EnumPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/EnumPropertyEditorControl.java new file mode 100644 index 00000000..2b007ce6 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/EnumPropertyEditorControl.java @@ -0,0 +1,30 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.util.EditorUtils; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.VarTable; +import org.jetbrains.annotations.NotNull; + +/** + * The property control to edit enum values. + * + * @author JavaSaBr + */ +public class EnumPropertyEditorControl> extends ComboBoxPropertyEditorControl { + + protected EnumPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + + var defaultValue = ClassUtils.unsafeCast(definition.requireDefaultValue()); + var enumConstants = EditorUtils.getEnumValues(defaultValue.getClass()); + + comboBox.getItems() + .addAll(enumConstants); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/ExternalFileResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ExternalFileResourcePropertyControl.java new file mode 100644 index 00000000..4f1f35e0 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ExternalFileResourcePropertyControl.java @@ -0,0 +1,72 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.dialog.file.chooser.ExternalFileEditorDialog; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.dialog.file.chooser.ExternalFileEditorDialog; +import com.ss.rlib.common.util.VarTable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The control to edit files from file system. + * + * @author JavaSaBr + */ +public class ExternalFileResourcePropertyControl extends ResourcePropertyEditorControl { + + /** + * The target extension. + */ + @Nullable + private final String extension; + + public ExternalFileResourcePropertyControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.extension = definition.getExtension(); + } + + @Override + @FxThread + protected void chooseNewResource() { + super.chooseNewResource(); + + var dialog = new ExternalFileEditorDialog(this::openExternalFile); + dialog.setTitleText(Messages.ASSET_EDITOR_DIALOG_TITLE); + dialog.setInitDirectory(Paths.get(System.getProperty("user.home"))); + dialog.show(); + } + + /** + * Handle selected file. + * + * @param path the selected file. + */ + @FxThread + private void openExternalFile(@NotNull Path path) { + setPropertyValue(path); + changed(); + reload(); + } + + @Override + @FxThread + protected void reloadImpl() { + + resourceLabel.setText(getPropertyValueOpt() + .map(Path::toString) + .orElse(NOT_SELECTED)); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/FileAssetResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/FileAssetResourcePropertyControl.java new file mode 100644 index 00000000..d5a81181 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/FileAssetResourcePropertyControl.java @@ -0,0 +1,74 @@ +package com.ss.builder.plugin.api.property.control; + +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The control to edit file values from asset folder. + * + * @author JavaSaBr + */ +public class FileAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { + + private static final Predicate> ACTION_TESTER = + type -> type == NewFileAction.class; + + /** + * The list of target extensions. + */ + @NotNull + private final Array extensions; + + public FileAssetResourcePropertyControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.extensions = ArrayFactory.asArray(notNull(definition.getExtension())); + } + + @Override + @FromAnyThread + public @NotNull Predicate> getActionTester() { + return ACTION_TESTER; + } + + @Override + @FromAnyThread + protected @NotNull Array getExtensions() { + return extensions; + } + + @Override + @FxThread + protected void chooseNewResource(@NotNull Path file) { + setPropertyValue(EditorUtils.requireAssetFile(file)); + super.chooseNewResource(file); + } + + @Override + @FxThread + protected void reloadImpl() { + + resourceLabel.setText(getPropertyValueOpt() + .map(EditorUtils::toAssetPath) + .orElse(NOT_SELECTED)); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/FloatPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/FloatPropertyEditorControl.java new file mode 100644 index 00000000..e76640a2 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/FloatPropertyEditorControl.java @@ -0,0 +1,38 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.rlib.common.util.ExtMath; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.control.input.FloatTextField; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit float values. + * + * @author JavaSaBr + */ +public class FloatPropertyEditorControl extends NumberPropertyEditorControl { + + public FloatPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + @Override + @FxThread + protected @NotNull FloatTextField createField() { + return new FloatTextField(); + } + + @Override + @FxThread + protected void reloadImpl() { + valueField.setValue(ExtMath.zeroIfNull(getPropertyValue())); + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/FolderAssetResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/FolderAssetResourcePropertyControl.java new file mode 100644 index 00000000..46750786 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/FolderAssetResourcePropertyControl.java @@ -0,0 +1,68 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.component.asset.tree.context.menu.action.NewFileAction; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.VarTable; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * The control to edit folder values from asset folder. + * + * @author JavaSaBr + */ +public class FolderAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { + + private static final Predicate> ACTION_TESTER = + type -> type == NewFileAction.class; + + public FolderAssetResourcePropertyControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + @Override + @FromAnyThread + public @NotNull Predicate> getActionTester() { + return ACTION_TESTER; + } + + @Override + @FxThread + protected void chooseNewResource() { + UiUtils.openFolderAssetDialog(this::chooseNewResource, getActionTester()); + } + + @Override + @FxThread + protected void chooseNewResource(@NotNull Path file) { + setPropertyValue(EditorUtils.requireAssetFile(file)); + super.chooseNewResource(file); + } + + @Override + @FxThread + protected void reloadImpl() { + + resourceLabel.setText(getPropertyValueOpt() + .map(EditorUtils::toAssetPath) + .filter(StringUtils::isEmpty) + .orElse("/")); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/GeometryAssetResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/GeometryAssetResourcePropertyControl.java similarity index 78% rename from src/main/java/com/ss/editor/plugin/api/property/control/GeometryAssetResourcePropertyControl.java rename to src/main/java/com/ss/builder/plugin/api/property/control/GeometryAssetResourcePropertyControl.java index f7beb1ac..19f6dd64 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/GeometryAssetResourcePropertyControl.java +++ b/src/main/java/com/ss/builder/plugin/api/property/control/GeometryAssetResourcePropertyControl.java @@ -1,11 +1,12 @@ -package com.ss.editor.plugin.api.property.control; +package com.ss.builder.plugin.api.property.control; import com.jme3.asset.AssetManager; import com.jme3.asset.ModelKey; import com.jme3.scene.Geometry; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.util.NodeUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.NodeUtils; import com.ss.rlib.common.util.VarTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/IntegerPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/IntegerPropertyEditorControl.java new file mode 100644 index 00000000..ad923c7c --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/IntegerPropertyEditorControl.java @@ -0,0 +1,38 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.rlib.common.util.ExtMath; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.control.input.IntegerTextField; +import org.jetbrains.annotations.NotNull; + +/** + * The property control to edit integer values. + * + * @author JavaSaBr + */ +public class IntegerPropertyEditorControl extends NumberPropertyEditorControl { + + public IntegerPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + @Override + @FxThread + protected @NotNull IntegerTextField createField() { + return new IntegerTextField(); + } + + @Override + @FxThread + protected void reloadImpl() { + valueField.setValue(ExtMath.zeroIfNull(getPropertyValue())); + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/NumberPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/NumberPropertyEditorControl.java new file mode 100644 index 00000000..f7c7de0e --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/NumberPropertyEditorControl.java @@ -0,0 +1,42 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.control.input.NumberTextField; +import org.jetbrains.annotations.NotNull; + +/** + * The property control to edit integer values. + * + * @author JavaSaBr + */ +public abstract class NumberPropertyEditorControl> extends + TypedTextFieldPropertyEditorControl { + + public NumberPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + /** + * Set min/max values. + * + * @param min the min value. + * @param max the max value. + */ + @FxThread + public void setMinMax(T min, T max) { + valueField.setMinMax(min, max); + } + + @Override + @FxThread + protected void changedImpl() { + setPropertyValue(valueField.getValue()); + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ObjectFromListPropertyEditorControl.java similarity index 82% rename from src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java rename to src/main/java/com/ss/builder/plugin/api/property/control/ObjectFromListPropertyEditorControl.java index 97c52f4d..d281c536 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ObjectFromListPropertyEditorControl.java @@ -1,6 +1,6 @@ -package com.ss.editor.plugin.api.property.control; +package com.ss.builder.plugin.api.property.control; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; @@ -19,7 +19,6 @@ public ObjectFromListPropertyEditorControl( @NotNull Array options ) { super(vars, definition, validationCallback); - var comboBox = getComboBox(); options.forEach(comboBox.getItems(), (option, items) -> items.add(option)); } diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControl.java similarity index 80% rename from src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java rename to src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControl.java index 222888d3..d518a0e8 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java +++ b/src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControl.java @@ -1,12 +1,17 @@ -package com.ss.editor.plugin.api.property.control; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; import com.ss.editor.extension.property.EditablePropertyType; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.util.UiUtils; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.dialog.AbstractSimpleEditorDialog; +import com.ss.builder.fx.util.UiUtils; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.fx.util.FxUtils; @@ -17,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; +import java.util.Optional; /** * The base implementation of an editor control to edit properties on the factory dialog. @@ -84,6 +90,11 @@ public class PropertyEditorControl extends HBox { */ private boolean ignoreListener; + /** + * The flag to mark this control that this control was constructed fully. + */ + private boolean constructed; + protected PropertyEditorControl( @NotNull VarTable vars, @NotNull PropertyDefinition definition, @@ -105,14 +116,6 @@ protected PropertyEditorControl( setOnKeyReleased(UiUtils::consumeIfIsNotHotKey); setOnKeyPressed(UiUtils::consumeIfIsNotHotKey); - createComponents(); - - setIgnoreListener(true); - try { - reload(); - } finally { - setIgnoreListener(false); - } FxUtils.addClass(this, CssClasses.PROPERTY_EDITOR_CONTROL); } @@ -124,6 +127,7 @@ protected PropertyEditorControl( public void checkDependency() { var dependencies = getDependencies(); + if (dependencies.isEmpty()) { return; } @@ -194,21 +198,42 @@ public void checkDependency() { */ @FxThread public void reload() { + setIgnoreListener(true); + try { + reloadImpl(); + } finally { + setIgnoreListener(false); + } } + /** + * Reload value of this control. + */ @FxThread - protected void change() { - if (isIgnoreListener()) return; - changeImpl(); + protected void reloadImpl() { } @FxThread - protected void changeImpl() { + protected void changed() { + if (!isIgnoreListener()) { + changedImpl(); + } + } + + @FxThread + protected void changedImpl() { validationCallback.run(); } @FxThread - protected void createComponents() { + public void postConstruct() { + + if (constructed) { + return; + } else { + constructed = true; + } + setAlignment(Pos.CENTER_RIGHT); propertyNameLabel = new Label(getName() + ":"); @@ -239,6 +264,20 @@ protected void createComponents() { return vars.get(id); } + /** + * Get the current property value. + * + * @return the optional value of the current property value. + */ + @FromAnyThread + protected @NotNull Optional getPropertyValueOpt() { + if (!vars.has(id)) { + return Optional.empty(); + } else { + return Optional.of(vars.get(id)); + } + } + /** * Set the new current property value. * diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java b/src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControlFactory.java similarity index 76% rename from src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java rename to src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControlFactory.java index 1c3fb521..aacc942c 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java +++ b/src/main/java/com/ss/builder/plugin/api/property/control/PropertyEditorControlFactory.java @@ -1,7 +1,8 @@ -package com.ss.editor.plugin.api.property.control; +package com.ss.builder.plugin.api.property.control; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.VarTable; import org.jetbrains.annotations.NotNull; @@ -27,10 +28,32 @@ public class PropertyEditorControlFactory { @NotNull Runnable validation ) { + var control = buildImpl(vars, definition, validation); + control.postConstruct(); + control.reload(); + + return control; + } + + @FxThread + private static @NotNull PropertyEditorControl buildImpl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validation + ) { + + var min = definition.getMin(); + var max = definition.getMax(); + switch (definition.getPropertyType()) { case FLOAT: { + var control = new FloatPropertyEditorControl(vars, definition, validation); - control.setMinMax(definition.getMin(), definition.getMax()); + + if (!Float.isNaN(min) && !Float.isNaN(max)) { + control.setMinMax(min, max); + } + return control; } case COLOR: @@ -38,8 +61,13 @@ public class PropertyEditorControlFactory { case BOOLEAN: return new BooleanPropertyEditorControl(vars, definition, validation); case INTEGER: { + var control = new IntegerPropertyEditorControl(vars, definition, validation); - control.setMinMax(definition.getMin(), definition.getMax()); + + if (!Float.isNaN(min) && !Float.isNaN(max)) { + control.setMinMax((int) min, (int) max); + } + return control; } case VECTOR_3F: diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/ResourcePropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/ResourcePropertyEditorControl.java new file mode 100644 index 00000000..b82bff32 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/ResourcePropertyEditorControl.java @@ -0,0 +1,146 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.Messages; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.Icons; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.DynamicIconSupport; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.input.DragEvent; +import javafx.scene.layout.HBox; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.nio.file.Path; + +/** + * The control to edit resource values. + * + * @author JavaSaBr + */ +public abstract class ResourcePropertyEditorControl extends PropertyEditorControl { + + protected static final String NOT_SELECTED = + Messages.RESOURCE_PROPERTY_EDIT_CONTROL_NOTHING_IS_SELECTED; + + /** + * The label with name of the resource. + */ + @NotNull + protected final Label resourceLabel; + + protected ResourcePropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.resourceLabel = new Label(NOT_SELECTED); + setOnDragOver(this::dragOver); + setOnDragDropped(this::dragDropped); + setOnDragExited(this::dragExited); + FxUtils.addClass(this, CssClasses.PROPERTY_CONTROL_RESOURCE); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + var changeButton = new Button(); + changeButton.setGraphic(new ImageView(Icons.ADD_16)); + + var removeButton = new Button(); + removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); + removeButton.disableProperty() + .bind(resourceLabel.textProperty().isEqualTo(NOT_SELECTED)); + + var container = new HBox(resourceLabel, changeButton, removeButton); + container.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + resourceLabel.prefWidthProperty() + .bind(container.widthProperty()); + + FxControlUtils.onAction(changeButton, this::chooseNewResource); + FxControlUtils.onAction(removeButton, this::removeCurrentResource); + + FxUtils.addClass(container, + CssClasses.DEF_HBOX, CssClasses.TEXT_INPUT_CONTAINER) + .addClass(changeButton, removeButton, + CssClasses.FLAT_BUTTON, CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON) + .addClass(resourceLabel, + CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL); + + FxUtils.addChild(this, container); + + DynamicIconSupport.addSupport(changeButton); + } + + /** + * Choose a new resource. + */ + @FxThread + protected void chooseNewResource() { + } + + /** + * Remove the current resource. + */ + @FxThread + protected void removeCurrentResource() { + setPropertyValue(null); + changed(); + reload(); + } + + /** + * Handle grad exiting. + */ + @FxThread + private void dragExited(@NotNull DragEvent dragEvent) { + } + + /** + * Handle dropped files to editor. + */ + @FxThread + private void dragDropped(@NotNull DragEvent dragEvent) { + UiUtils.handleDroppedFile(dragEvent, this::chooseNewResource); + } + + /** + * Choose a new resource. + * + * @param file the resource's file. + */ + @FxThread + protected void chooseNewResource(@NotNull Path file) { + } + + /** + * Handle drag over. + */ + @FxThread + private void dragOver(@NotNull DragEvent dragEvent) { ; + UiUtils.acceptIfHasFile(dragEvent, this::canAccept); + } + + @FxThread + protected boolean canAccept(@NotNull File file) { + return false; + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/SpatialAssetResourcePropertyControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/SpatialAssetResourcePropertyControl.java new file mode 100644 index 00000000..96c41dd4 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/SpatialAssetResourcePropertyControl.java @@ -0,0 +1,94 @@ +package com.ss.builder.plugin.api.property.control; + +import static com.ss.builder.util.EditorUtils.toAssetPath; +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import com.jme3.asset.AssetManager; +import com.jme3.asset.ModelKey; +import com.jme3.scene.Spatial; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.util.EditorUtils; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.util.FileUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.nio.file.Path; + +/** + * The control to edit spatial values from asset. + * + * @author JavaSaBr + */ +public class SpatialAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { + + private static final Array EXTENSIONS = + Array.of(FileExtensions.JME_OBJECT); + + public SpatialAssetResourcePropertyControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + } + + @Override + @FromAnyThread + protected @NotNull Array getExtensions() { + return EXTENSIONS; + } + + @Override + @FxThread + protected void chooseNewResource(@NotNull Path file) { + + var assetManager = EditorUtils.getAssetManager(); + + var assetFile = EditorUtils.requireAssetFile(file); + var modelKey = new ModelKey(EditorUtils.toAssetPath(assetFile)); + var spatial = findResource(assetManager, modelKey); + + setPropertyValue(unsafeCast(spatial)); + + super.chooseNewResource(file); + } + + /** + * Find a resource rom asset folder by the model key. + * + * @param assetManager the asset manager. + * @param modelKey the model key. + * @return the target resource. + */ + @FxThread + protected @Nullable T findResource(@NotNull AssetManager assetManager, @NotNull ModelKey modelKey) { + return unsafeCast(assetManager.loadModel(modelKey)); + } + + @Override + @FxThread + protected boolean canAccept(@NotNull File file) { + return EXTENSIONS.contains(FileUtils.getExtension(file.getName())); + } + + @Override + @FxThread + protected void reloadImpl() { + + var model = getPropertyValue(); + var rootKey = EditorUtils.findRootKey(model); + + resourceLabel.setText(rootKey == null ? NOT_SELECTED : rootKey + "[" + model.getName() + "]"); + + super.reloadImpl(); + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/StringFromListPropertyEditorControl.java similarity index 77% rename from src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java rename to src/main/java/com/ss/builder/plugin/api/property/control/StringFromListPropertyEditorControl.java index 8ece920c..a2b551d9 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java +++ b/src/main/java/com/ss/builder/plugin/api/property/control/StringFromListPropertyEditorControl.java @@ -1,9 +1,12 @@ -package com.ss.editor.plugin.api.property.control; +package com.ss.builder.plugin.api.property.control; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.SimpleStringSuggestionProvider; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.SimpleStringSuggestionProvider; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.SimpleStringSuggestionProvider; import com.ss.rlib.common.util.VarTable; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.fx.util.FxControlUtils; @@ -26,7 +29,6 @@ public StringFromListPropertyEditorControl( ) { super(vars, definition, validationCallback); - var comboBox = getComboBox(); options.forEach(comboBox.getItems(), (option, items) -> items.add(option.toString())); @@ -41,8 +43,10 @@ public StringFromListPropertyEditorControl( var binding = new AutoCompletionTextFieldBinding(editor, new SimpleStringSuggestionProvider(comboBox.getItems())); + binding.setOnAutoCompleted(event -> selectionModel.select(event.getCompletion())); - binding.prefWidthProperty().bind(comboBox.widthProperty().multiply(1.3)); + binding.prefWidthProperty() + .bind(comboBox.widthProperty().multiply(1.3)); FxControlUtils.onSelectedItemChange(comboBox, newValue -> { var executorManager = ExecutorManager.getInstance(); @@ -53,7 +57,7 @@ public StringFromListPropertyEditorControl( CssClasses.TRANSPARENT_TEXT_FIELD, CssClasses.TEXT_FIELD_IN_COMBO_BOX); - reload(); + reloadImpl(); } finally { setIgnoreListener(false); diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/StringPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/StringPropertyEditorControl.java new file mode 100644 index 00000000..929c8955 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/StringPropertyEditorControl.java @@ -0,0 +1,68 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.control.TextField; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit string values. + * + * @author JavaSaBr + */ +public class StringPropertyEditorControl extends PropertyEditorControl { + + /** + * The value field. + */ + @NotNull + private final TextField valueField; + + protected StringPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.valueField = new TextField(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + valueField.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onTextChange(valueField, this::changed); + + FxUtils.addClass(valueField, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(this, valueField); + } + + @Override + @FxThread + protected void reloadImpl() { + + valueField.setText(getPropertyValueOpt() + .orElse("")); + + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + setPropertyValue(valueField.getText()); + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java new file mode 100644 index 00000000..fa219a48 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java @@ -0,0 +1,60 @@ +package com.ss.builder.plugin.api.property.control; + +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.control.input.TypedTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The typed text field base property control. + * + * @author JavaSaBr + */ +public abstract class TypedTextFieldPropertyEditorControl> + extends PropertyEditorControl { + + /** + * The value field. + */ + @NotNull + protected final F valueField; + + protected TypedTextFieldPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.valueField = createField(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + valueField.prefWidthProperty() + .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); + + FxControlUtils.onTextChange(valueField, this::changed); + + FxUtils.addClass(valueField, + CssClasses.PROPERTY_CONTROL_COMBO_BOX); + + FxUtils.addChild(this, valueField); + } + + /** + * Create a new field. + * + * @return the new field. + */ + @FxThread + protected abstract @NotNull F createField(); +} diff --git a/src/main/java/com/ss/builder/plugin/api/property/control/Vector3fPropertyEditorControl.java b/src/main/java/com/ss/builder/plugin/api/property/control/Vector3fPropertyEditorControl.java new file mode 100644 index 00000000..0415fa9d --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/property/control/Vector3fPropertyEditorControl.java @@ -0,0 +1,119 @@ +package com.ss.builder.plugin.api.property.control; + +import com.jme3.math.Vector3f; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.plugin.api.property.PropertyDefinition; +import com.ss.builder.fx.css.CssClasses; +import com.ss.builder.fx.util.UiUtils; +import com.ss.rlib.common.util.VarTable; +import com.ss.rlib.fx.control.input.FloatTextField; +import com.ss.rlib.fx.util.FxControlUtils; +import com.ss.rlib.fx.util.FxUtils; +import javafx.scene.layout.GridPane; +import org.jetbrains.annotations.NotNull; + +/** + * The control to edit float values. + * + * @author JavaSaBr + */ +public class Vector3fPropertyEditorControl extends PropertyEditorControl { + + /** + * The field X. + */ + @NotNull + private final FloatTextField xField; + + /** + * The field Y. + */ + @NotNull + private final FloatTextField yField; + + /** + * The field Z. + */ + @NotNull + private final FloatTextField zField; + + protected Vector3fPropertyEditorControl( + @NotNull VarTable vars, + @NotNull PropertyDefinition definition, + @NotNull Runnable validationCallback + ) { + super(vars, definition, validationCallback); + this.xField = new FloatTextField(); + this.yField = new FloatTextField(); + this.zField = new FloatTextField(); + } + + @Override + @FxThread + public void postConstruct() { + super.postConstruct(); + + var resultWidth = widthProperty() + .multiply(DEFAULT_FIELD_W_PERCENT); + + var gridPane = new GridPane(); + gridPane.prefWidthProperty() + .bind(resultWidth); + + var fieldWidth = gridPane.widthProperty() + .divide(3); + + xField.prefWidthProperty() + .bind(fieldWidth); + yField.prefWidthProperty() + .bind(fieldWidth); + zField.prefWidthProperty() + .bind(fieldWidth); + + gridPane.add(xField, 0, 0); + gridPane.add(yField, 1, 0); + gridPane.add(zField, 2, 0); + + FxControlUtils.onValueChange(xField, this::changed); + FxControlUtils.onValueChange(yField, this::changed); + FxControlUtils.onValueChange(zField, this::changed); + + FxUtils.addClass(gridPane, + CssClasses.DEF_GRID_PANE, CssClasses.TEXT_INPUT_CONTAINER) + .addClass(xField, yField, zField, + CssClasses.TRANSPARENT_TEXT_FIELD, + CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD); + + FxUtils.addChild(this, gridPane); + + UiUtils.addFocusBinding(gridPane, xField, yField, zField); + } + + @Override + @FxThread + protected void reloadImpl() { + + var value = getPropertyValue(); + + xField.setValue(value == null ? 0 : value.getX()); + yField.setValue(value == null ? 0 : value.getY()); + zField.setValue(value == null ? 0 : value.getZ()); + + super.reloadImpl(); + } + + @Override + @FxThread + protected void changedImpl() { + + setPropertyValue(new Vector3f( + xField.getPrimitiveValue(), + yField.getPrimitiveValue(), + zField.getPrimitiveValue())); + + super.changedImpl(); + } +} diff --git a/src/main/java/com/ss/editor/plugin/api/settings/SettingsCategory.java b/src/main/java/com/ss/builder/plugin/api/settings/SettingsCategory.java similarity index 91% rename from src/main/java/com/ss/editor/plugin/api/settings/SettingsCategory.java rename to src/main/java/com/ss/builder/plugin/api/settings/SettingsCategory.java index b196026f..323de37c 100644 --- a/src/main/java/com/ss/editor/plugin/api/settings/SettingsCategory.java +++ b/src/main/java/com/ss/builder/plugin/api/settings/SettingsCategory.java @@ -1,6 +1,7 @@ -package com.ss.editor.plugin.api.settings; +package com.ss.builder.plugin.api.settings; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/plugin/api/settings/SettingsPropertyDefinition.java b/src/main/java/com/ss/builder/plugin/api/settings/SettingsPropertyDefinition.java similarity index 93% rename from src/main/java/com/ss/editor/plugin/api/settings/SettingsPropertyDefinition.java rename to src/main/java/com/ss/builder/plugin/api/settings/SettingsPropertyDefinition.java index b1200e25..299ca687 100644 --- a/src/main/java/com/ss/editor/plugin/api/settings/SettingsPropertyDefinition.java +++ b/src/main/java/com/ss/builder/plugin/api/settings/SettingsPropertyDefinition.java @@ -1,8 +1,9 @@ -package com.ss.editor.plugin.api.settings; +package com.ss.builder.plugin.api.settings; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.editor.extension.property.EditablePropertyType; -import com.ss.editor.plugin.api.property.PropertyDefinition; +import com.ss.builder.plugin.api.property.PropertyDefinition; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/plugin/api/settings/SettingsProvider.java b/src/main/java/com/ss/builder/plugin/api/settings/SettingsProvider.java similarity index 91% rename from src/main/java/com/ss/editor/plugin/api/settings/SettingsProvider.java rename to src/main/java/com/ss/builder/plugin/api/settings/SettingsProvider.java index 05a4e2a4..d00011df 100644 --- a/src/main/java/com/ss/editor/plugin/api/settings/SettingsProvider.java +++ b/src/main/java/com/ss/builder/plugin/api/settings/SettingsProvider.java @@ -1,6 +1,7 @@ -package com.ss.editor.plugin.api.settings; +package com.ss.builder.plugin.api.settings; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/plugin/api/settings/SettingsProviderRegistry.java b/src/main/java/com/ss/builder/plugin/api/settings/SettingsProviderRegistry.java new file mode 100644 index 00000000..7e2ddde9 --- /dev/null +++ b/src/main/java/com/ss/builder/plugin/api/settings/SettingsProviderRegistry.java @@ -0,0 +1,96 @@ +package com.ss.builder.plugin.api.settings; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.DefaultSettingsProvider; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.plugin.extension.ExtensionPoint; +import com.ss.rlib.common.plugin.extension.ExtensionPointManager; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The registry of all settings providers. + * + * @author JavaSaBr + */ +public class SettingsProviderRegistry { + + private static final Logger LOGGER = LoggerManager.getLogger(SettingsProviderRegistry.class); + + /** + * @see SettingsProvider + */ + public static final String EP_PROVIDERS = "SettingsProviderRegistry#providers"; + + private static final ExtensionPoint PROVIDERS = + ExtensionPointManager.register(EP_PROVIDERS); + + private static final SettingsProviderRegistry INSTANCE = new SettingsProviderRegistry(); + + @FromAnyThread + public static @NotNull SettingsProviderRegistry getInstance() { + return INSTANCE; + } + + private SettingsProviderRegistry() { + PROVIDERS.register(new DefaultSettingsProvider()); + LOGGER.info("initialized."); + } + + /** + * Get all available settings property definitions. + * + * @return all available settings property definitions. + */ + @FxThread + public @NotNull Array getDefinitions() { + + var result = Array.ofType(SettingsPropertyDefinition.class); + + for (var settingsProvider : PROVIDERS.getExtensions()) { + result.addAll(settingsProvider.getDefinitions()); + } + + return result; + } + + /** + * Check the property if this property requires restarting of editor. + * + * @param propertyId the property id. + * @return true if need to restart to apply changes for this property. + */ + @FxThread + public boolean isRequiredRestart(@NotNull String propertyId) { + return PROVIDERS.getExtensions().stream() + .anyMatch(settingsProvider -> settingsProvider.isRequiredRestart(propertyId)); + } + + /** + * Check the property if this property requires updating of classpath. + * + * @param propertyId the property id. + * @return true if need to update classpath to apply changes for this property. + */ + @FxThread + public boolean isRequiredUpdateClasspath(@NotNull String propertyId) { + return PROVIDERS.getExtensions().stream() + .anyMatch(settingsProvider -> settingsProvider.isRequiredUpdateClasspath(propertyId)); + } + + /** + * Check the property if this property requires reshaping of 3D view. + * + * @param propertyId the property id. + * @return true if need to reshape 3D view to apply changes for this property. + */ + @FxThread + public boolean isRequiredReshape3DView(@NotNull String propertyId) { + return PROVIDERS.getExtensions().stream() + .anyMatch(settingsProvider -> settingsProvider.isRequiredReshape3DView(propertyId)); + } +} diff --git a/src/main/java/com/ss/editor/remote/control/client/ClientCommand.java b/src/main/java/com/ss/builder/remote/control/client/ClientCommand.java similarity index 82% rename from src/main/java/com/ss/editor/remote/control/client/ClientCommand.java rename to src/main/java/com/ss/builder/remote/control/client/ClientCommand.java index 4f3bc524..9785477c 100644 --- a/src/main/java/com/ss/editor/remote/control/client/ClientCommand.java +++ b/src/main/java/com/ss/builder/remote/control/client/ClientCommand.java @@ -1,6 +1,6 @@ -package com.ss.editor.remote.control.client; +package com.ss.builder.remote.control.client; -import com.ss.editor.annotation.BackgroundThread; +import com.ss.builder.annotation.BackgroundThread; import com.ss.rlib.common.network.ConnectionOwner; import com.ss.rlib.common.network.packet.impl.AbstractReadablePacket; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/remote/control/client/InitLocalClasspathClientCommand.java b/src/main/java/com/ss/builder/remote/control/client/InitLocalClasspathClientCommand.java similarity index 79% rename from src/main/java/com/ss/editor/remote/control/client/InitLocalClasspathClientCommand.java rename to src/main/java/com/ss/builder/remote/control/client/InitLocalClasspathClientCommand.java index 3d5e3351..4aea63d5 100644 --- a/src/main/java/com/ss/editor/remote/control/client/InitLocalClasspathClientCommand.java +++ b/src/main/java/com/ss/builder/remote/control/client/InitLocalClasspathClientCommand.java @@ -1,11 +1,11 @@ -package com.ss.editor.remote.control.client; +package com.ss.builder.remote.control.client; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.manager.ClasspathManager; +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.manager.ClasspathManager; import com.ss.rlib.common.network.ConnectionOwner; import com.ss.rlib.common.network.annotation.PacketDescription; import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.ArrayFactory; +import com.ss.rlib.common.util.array.Array; import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; @@ -24,7 +24,7 @@ public class InitLocalClasspathClientCommand extends ClientCommand { @BackgroundThread protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { - var libraries = ArrayFactory.newArray(Path.class); + var libraries = Array.ofType(Path.class); for (int i = 0, length = readInt(buffer); i < length; i++) { libraries.add(Paths.get(readString(buffer))); diff --git a/src/main/java/com/ss/builder/remote/control/client/LoadLocalClassesClientCommand.java b/src/main/java/com/ss/builder/remote/control/client/LoadLocalClassesClientCommand.java new file mode 100644 index 00000000..b031e385 --- /dev/null +++ b/src/main/java/com/ss/builder/remote/control/client/LoadLocalClassesClientCommand.java @@ -0,0 +1,36 @@ +package com.ss.builder.remote.control.client; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.network.ConnectionOwner; +import com.ss.rlib.common.network.annotation.PacketDescription; +import com.ss.rlib.common.util.StringUtils; +import org.jetbrains.annotations.NotNull; + +import java.nio.ByteBuffer; +import java.nio.file.Paths; + +/** + * The command to load local libraries in jMB. + * + * @author JavaSaBr + */ +@PacketDescription(id = 3) +public class LoadLocalClassesClientCommand extends ClientCommand { + + @Override + @BackgroundThread + protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { + + var outputPath = readString(buffer); + var output = StringUtils.isEmpty(outputPath) ? null : Paths.get(outputPath); + + ClasspathManager.getInstance() + .loadLocalClasses(output); + + ExecutorManager.getInstance() + .addJmeTask(EditorUtils::clearAssetCache); + } +} diff --git a/src/main/java/com/ss/builder/remote/control/client/LoadLocalLibrariesClientCommand.java b/src/main/java/com/ss/builder/remote/control/client/LoadLocalLibrariesClientCommand.java new file mode 100644 index 00000000..c44ebc77 --- /dev/null +++ b/src/main/java/com/ss/builder/remote/control/client/LoadLocalLibrariesClientCommand.java @@ -0,0 +1,35 @@ +package com.ss.builder.remote.control.client; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.manager.ClasspathManager; +import com.ss.rlib.common.network.ConnectionOwner; +import com.ss.rlib.common.network.annotation.PacketDescription; +import com.ss.rlib.common.util.array.Array; +import org.jetbrains.annotations.NotNull; + +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The command to load local libraries in jMB. + * + * @author JavaSaBr + */ +@PacketDescription(id = 2) +public class LoadLocalLibrariesClientCommand extends ClientCommand { + + @Override + @BackgroundThread + protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { + + var libraries = Array.ofType(Path.class); + + for (int i = 0, length = readInt(buffer); i < length; i++) { + libraries.add(Paths.get(readString(buffer))); + } + + ClasspathManager.getInstance() + .loadLocalLibraries(libraries); + } +} diff --git a/src/main/java/com/ss/builder/remote/control/client/OpenFileClientCommand.java b/src/main/java/com/ss/builder/remote/control/client/OpenFileClientCommand.java new file mode 100644 index 00000000..4b840570 --- /dev/null +++ b/src/main/java/com/ss/builder/remote/control/client/OpenFileClientCommand.java @@ -0,0 +1,85 @@ +package com.ss.builder.remote.control.client; + +import com.ss.builder.annotation.BackgroundThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.component.bar.action.OpenAssetAction; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.AssetComponentLoadedEvent; +import com.ss.builder.fx.event.impl.RequestedOpenFileEvent; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.util.EditorUtils; +import com.ss.rlib.common.network.ConnectionOwner; +import com.ss.rlib.common.network.annotation.PacketDescription; +import javafx.event.EventHandler; +import org.jetbrains.annotations.NotNull; + +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The command to open a file. + * + * @author JavaSaBr + */ +@PacketDescription(id = 1) +public class OpenFileClientCommand extends ClientCommand { + + @Override + @BackgroundThread + protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { + + var assetPath = Paths.get(readString(buffer)); + var fileToOpen = Paths.get(readString(buffer)); + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + + if (assetPath.equals(currentAsset)) { + openFileInCurrentAsset(fileToOpen); + } else { + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + + var action = new OpenAssetAction(); + action.openAssetFolder(assetPath); + + var eventManager = FxEventManager.getInstance(); + var eventHandler = new EventHandler() { + + @Override + public void handle(@NotNull AssetComponentLoadedEvent event) { + eventManager.removeEventHandler(AssetComponentLoadedEvent.EVENT_TYPE, this); + openFile(fileToOpen); + } + }; + + eventManager.addEventHandler(AssetComponentLoadedEvent.EVENT_TYPE, eventHandler); + }); + + } + } + + @FromAnyThread + private void openFileInCurrentAsset(@NotNull Path fileToOpen) { + ExecutorManager.getInstance() + .addFxTask(() -> openFile(fileToOpen)); + } + + /** + * Open the file. + * + * @param fileToOpen the file. + */ + @FxThread + private void openFile(@NotNull Path fileToOpen) { + + FxEventManager.getInstance() + .notify(new RequestedOpenFileEvent(fileToOpen)); + + EditorUtils.requestFxFocus(); + } +} diff --git a/src/main/java/com/ss/editor/task/CheckNewVersionTask.java b/src/main/java/com/ss/builder/task/CheckNewVersionTask.java similarity index 93% rename from src/main/java/com/ss/editor/task/CheckNewVersionTask.java rename to src/main/java/com/ss/builder/task/CheckNewVersionTask.java index f0013723..66a57ac0 100644 --- a/src/main/java/com/ss/editor/task/CheckNewVersionTask.java +++ b/src/main/java/com/ss/builder/task/CheckNewVersionTask.java @@ -1,9 +1,9 @@ -package com.ss.editor.task; +package com.ss.builder.task; import static org.apache.http.impl.client.HttpClients.createMinimal; -import com.ss.editor.Messages; -import com.ss.editor.config.Config; -import com.ss.editor.util.EditorUtil; +import com.ss.builder.Messages; +import com.ss.builder.config.Config; +import com.ss.builder.util.EditorUtils; import com.ss.rlib.common.logging.Logger; import com.ss.rlib.common.logging.LoggerManager; import com.ss.rlib.common.plugin.Version; @@ -72,7 +72,7 @@ public void run() { Platform.runLater(() -> { - var hostServices = EditorUtil.getHostServices(); + var hostServices = EditorUtils.getHostServices(); var hyperlink = new Hyperlink(Messages.CHECK_NEW_VERSION_DIALOG_HYPERLINK + targetLink); hyperlink.setOnAction(event -> hostServices.showDocument(targetLink)); diff --git a/src/main/java/com/ss/editor/util/AnimationUtils.java b/src/main/java/com/ss/builder/util/AnimationUtils.java similarity index 97% rename from src/main/java/com/ss/editor/util/AnimationUtils.java rename to src/main/java/com/ss/builder/util/AnimationUtils.java index cc02c342..344dcfaf 100644 --- a/src/main/java/com/ss/editor/util/AnimationUtils.java +++ b/src/main/java/com/ss/builder/util/AnimationUtils.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; @@ -6,7 +6,8 @@ import com.jme3.animation.Track; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.rlib.common.util.ClassUtils; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/util/AudioNodeUtils.java b/src/main/java/com/ss/builder/util/AudioNodeUtils.java new file mode 100644 index 00000000..4e84b9d4 --- /dev/null +++ b/src/main/java/com/ss/builder/util/AudioNodeUtils.java @@ -0,0 +1,62 @@ +package com.ss.builder.util; + +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioKey; +import com.jme3.audio.AudioNode; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.rlib.common.util.ReflectionUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * The utility class to work with audio nodes. + * + * @author JavaSaBr + */ +public class AudioNodeUtils { + + private static final Field AUDIO_DATA_FIELD = + ReflectionUtils.getUnsafeField(AudioNode.class, "audioKey"); + + private static final Field AUDIO_KEY_FIELD = + ReflectionUtils.getUnsafeField(AudioNode.class, "data"); + + /** + * Update audio data for an audio node. + * + * @param audioNode the audio node. + * @param audioData the audio data. + * @param audioKey the audio key. + */ + @JmeThread + public static void updateData( + @NotNull AudioNode audioNode, + @Nullable AudioData audioData, + @Nullable AudioKey audioKey + ) { + try { + AUDIO_DATA_FIELD.set(audioNode, audioData); + AUDIO_KEY_FIELD.set(audioNode, audioKey); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + /** + * Get an audio key from the audio node. + * + * @param audioNode the audio node. + * @return the audio key. + */ + @FromAnyThread + public static @Nullable AudioKey getAudioKey(@NotNull AudioNode audioNode) { + try { + return (AudioKey) AUDIO_KEY_FIELD.get(audioNode); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/ss/editor/util/ControlUtils.java b/src/main/java/com/ss/builder/util/ControlUtils.java similarity index 90% rename from src/main/java/com/ss/editor/util/ControlUtils.java rename to src/main/java/com/ss/builder/util/ControlUtils.java index 897b5477..6a77cd95 100644 --- a/src/main/java/com/ss/editor/util/ControlUtils.java +++ b/src/main/java/com/ss/builder/util/ControlUtils.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import static com.jme3.bullet.util.CollisionShapeFactory.createDynamicMeshShape; import static com.jme3.bullet.util.CollisionShapeFactory.createMeshShape; @@ -15,8 +15,10 @@ import com.jme3.scene.control.Control; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -91,6 +93,17 @@ public static boolean isEnabled(@NotNull Control control) { } } + /** + * Check enabled status of the control. + * + * @param control the control. + * @return true if this control isn't enabled. + */ + @FromAnyThread + public static boolean isNotEnabled(@NotNull Control control) { + return !isEnabled(control); + } + /** * Change the enabled status of the control. * diff --git a/src/main/java/com/ss/builder/util/EditorUtils.java b/src/main/java/com/ss/builder/util/EditorUtils.java new file mode 100644 index 00000000..eae3ebb3 --- /dev/null +++ b/src/main/java/com/ss/builder/util/EditorUtils.java @@ -0,0 +1,1080 @@ +package com.ss.builder.util; + +import static com.ss.rlib.common.util.ClassUtils.cast; +import static com.ss.rlib.common.util.ClassUtils.unsafeCast; +import static com.ss.rlib.common.util.ObjectUtils.notNull; +import static java.lang.ThreadLocal.withInitial; +import static java.util.stream.Collectors.toList; +import com.jme3.app.Application; +import com.jme3.app.state.AppStateManager; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetManager; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.input.InputManager; +import com.jme3.light.LightProbe; +import com.jme3.material.Material; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.system.JmeSystem; +import com.jme3.system.Platform; +import com.ss.builder.JfxApplication; +import com.ss.builder.JmeApplication; +import com.ss.builder.analytics.google.GAnalytics; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.config.EditorConfig; +import com.ss.builder.fx.event.FxEventManager; +import com.ss.builder.fx.event.impl.RequestedOpenFileEvent; +import com.ss.builder.fx.scene.EditorFxScene; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.manager.ClasspathManager; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.manager.ResourceManager; +import com.ss.builder.model.undo.editor.ChangeConsumer; +import com.ss.builder.model.undo.editor.SceneChangeConsumer; +import com.ss.editor.extension.scene.SceneLayer; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ClassUtils; +import com.ss.rlib.common.util.StringUtils; +import com.ss.rlib.common.util.array.Array; +import com.ss.rlib.common.util.dictionary.DictionaryFactory; +import com.ss.rlib.common.util.dictionary.ObjectDictionary; +import javafx.application.HostServices; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DataFormat; +import javafx.scene.input.Dragboard; +import javafx.stage.Stage; +import javafx.stage.Window; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.lang.StackWalker.Option; +import java.net.MalformedURLException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.function.Function; + +/** + * The class with utility methods for the Editor. + * + * @author JavaSaBr + */ +public abstract class EditorUtils { + + private static final Logger LOGGER = LoggerManager.getLogger(EditorUtils.class); + + public static final DataFormat JAVA_PARAM = new DataFormat("jMB.javaParam"); + public static final DataFormat GNOME_FILES = new DataFormat("x-special/gnome-copied-files"); + + private static final ThreadLocal LOCATE_DATE_FORMAT = withInitial(() -> + new SimpleDateFormat("HH:mm:ss:SSS")); + + private static final ThreadLocal, Enum[]>> ENUM_VALUES_LOCAL = + ThreadLocal.withInitial(DictionaryFactory::newObjectDictionary); + + private static JmeApplication jmeApplication; + private static JfxApplication jfxApplication; + + public static void setJmeApplication(@NotNull JmeApplication jmeApplication) { + + Class callerClass = StackWalker + .getInstance(Option.RETAIN_CLASS_REFERENCE) + .getCallerClass(); + + if (callerClass != JmeApplication.class) { + throw new IllegalArgumentException(); + } + + EditorUtils.jmeApplication = jmeApplication; + } + + public static void setJfxApplication(@NotNull JfxApplication jfxApplication) { + + Class callerClass = StackWalker + .getInstance(Option.RETAIN_CLASS_REFERENCE) + .getCallerClass(); + + if (callerClass != JfxApplication.class) { + throw new IllegalArgumentException(); + } + + EditorUtils.jfxApplication = jfxApplication; + } + + /** + * Get the asset manager. + * + * @return the asset manager. + */ + @FromAnyThread + public static @NotNull AssetManager getAssetManager() { + return jmeApplication.getAssetManager(); + } + + /** + * Get the input manager. + * + * @return the input manager. + */ + @FromAnyThread + public static @NotNull InputManager getInputManager() { + return jmeApplication.getInputManager(); + } + + /** + * Get the render manager. + * + * @return the render manager. + */ + @FromAnyThread + public static @NotNull RenderManager getRenderManager() { + return jmeApplication.getRenderManager(); + } + + /** + * Get the renderer. + * + * @return the renderer. + */ + @FromAnyThread + public static @NotNull Renderer getRenderer() { + return jmeApplication.getRenderer(); + } + + /** + * Get the root node. + * + * @return the root node. + */ + @JmeThread + public static @NotNull Node getRootNode(@NotNull Application application) { + + if (application instanceof JmeApplication) { + return ((JmeApplication) application).getRootNode(); + } + + throw new IllegalArgumentException("The application " + application + " doesn't have a root node."); + } + + /** + * Get the root node. + * + * @return the root node. + */ + @JmeThread + public static @NotNull Node getGlobalRootNode() { + return jmeApplication.getRootNode(); + } + + /** + * Get the preview node. + * + * @return the preview node. + */ + @JmeThread + public static @NotNull Node getPreviewNode() { + return jmeApplication.getPreviewNode(); + } + + /** + * Get the preview camera. + * + * @return the preview camera. + */ + @JmeThread + public static @NotNull Camera getPreviewCamera() { + return jmeApplication.getPreviewCamera(); + } + + /** + * Get the camera. + * + * @return the camera. + */ + @FromAnyThread + public static @NotNull Camera getGlobalCamera() { + return jmeApplication.getCamera(); + } + + /** + * Get the global filter post processor. + * + * @return the global filter post processor. + */ + @JmeThread + public static @NotNull FilterPostProcessor getGlobalFilterPostProcessor() { + return jmeApplication.getPostProcessor(); + } + + /** + * Get the default material. + * + * @return the default material. + */ + @FromAnyThread + public static @NotNull Material getDefaultMaterial() { + return jmeApplication.getDefaultMaterial(); + } + + /** + * Disable the global PBR light probe. + */ + @JmeThread + public static void disableGlobalLightProbe() { + jmeApplication.disableLightProbe(); + } + + /** + * Enable the global PBR light probe. + */ + @JmeThread + public static void enableGlobalLightProbe() { + jmeApplication.enableLightProbe(); + } + + /** + * Update the light probe. + * + * @param progressAdapter the progress adapter + */ + @JmeThread + public static void updateGlobalLightProbe(@NotNull JobProgressAdapter progressAdapter) { + jmeApplication.updateLightProbe(progressAdapter); + } + + /** + * Get the state manager. + * + * @return the state manager. + */ + @FromAnyThread + public static @NotNull AppStateManager getStateManager() { + return jmeApplication.getStateManager(); + } + + /** + * Gets the last opened window. + * + * @return the last opened window. + */ + @FxThread + public static @NotNull Window getFxLastWindow() { + return jfxApplication.getLastWindow(); + } + + /** + * Get the current JavaFX scene. + * + * @return the JavaFX scene. + */ + @FxThread + public static @NotNull EditorFxScene getFxScene() { + return jfxApplication.getScene(); + } + + /** + * Get the host services. + * + * @return the host services. + */ + @FxThread + public static @NotNull HostServices getHostServices() { + return jfxApplication.getHostServices(); + } + + /** + * Get the current stage of JavaFX. + * + * @return the current stage of JavaFX. + */ + @FxThread + public static @NotNull Stage getFxStage() { + return jfxApplication.getStage(); + } + + /** + * Register the opened new window. + * + * @param window the opened new window. + */ + @FromAnyThread + public static void addFxWindow(@NotNull Window window) { + jfxApplication.addWindow(window); + } + + /** + * Delete the closed window. + * + * @param window the closed window. + */ + @FromAnyThread + public static void removeFxWindow(@NotNull Window window) { + jfxApplication.removeWindow(window); + } + + /** + * Request focus to FX window. + */ + @FxThread + public static void requestFxFocus() { + jfxApplication.requestFocus(); + } + + /** + * Added files like files to copy to clipboard content. + * + * @param paths the list of files. + * @param content the content to store. + */ + @FxThread + public static @NotNull ClipboardContent addCopiedFile( + @NotNull Array paths, + @NotNull ClipboardContent content + ) { + + var files = paths.stream() + .map(Path::toFile) + .collect(toList()); + + content.putFiles(files); + content.put(EditorUtils.JAVA_PARAM, "copy"); + + var platform = JmeSystem.getPlatform(); + + if (platform == Platform.Linux64 || platform == Platform.Linux32) { + + var builder = new StringBuilder("copy\n"); + + paths.forEach(path -> builder.append(path.toUri() + .toASCIIString()) + .append('\n')); + + builder.delete(builder.length() - 1, builder.length()); + + var buffer = ByteBuffer.allocate(builder.length()); + + for (int i = 0, length = builder.length(); i < length; i++) { + buffer.put((byte) builder.charAt(i)); + } + + buffer.flip(); + + content.put(GNOME_FILES, buffer); + } + + return content; + } + + /** + * Check exists boolean. + * + * @param path the path to resource. + * @return true if the resource is exists. + */ + @FromAnyThread + public static boolean checkExists(@NotNull String path) { + var cs = EditorUtils.class; + return cs.getResource(path) != null || cs.getResource("/" + path) != null; + } + + /** + * Check exists boolean. + * + * @param path the path to resource. + * @param classLoader the class loader. + * @return true if the resource is exists. + */ + @FromAnyThread + public static boolean checkExists(@NotNull String path, @NotNull ClassLoader classLoader) { + return classLoader.getResource(path) != null || classLoader.getResource("/" + path) != null; + } + + /** + * Convert classpath path to external path. + * + * @param path the path to resource. + * @param classLoader the class loader. + * @return the external form or null. + */ + @FromAnyThread + public static @Nullable String toExternal(@NotNull String path, @NotNull ClassLoader classLoader) { + + if (!checkExists(path, classLoader)) { + return null; + } + + var resource = classLoader.getResource(path); + + if (resource == null) { + resource = classLoader.getResource("/" + path); + } + + return resource == null ? null : resource.toExternalForm(); + } + + /** + * Get an input stream. + * + * @param path the path to resource. + * @return the input stream of the resource or null. + */ + @FromAnyThread + public static @Nullable InputStream getInputStream(@NotNull String path) { + return JfxApplication.class.getResourceAsStream(path); + } + + /** + * Get an input stream or throw an exception. + * + * @param path the path to resource. + * @return the input stream of the resource or null. + */ + @FromAnyThread + public static @NotNull InputStream requireInputStream(@NotNull String path) { + return notNull(JfxApplication.class.getResourceAsStream(path)); + } + + /** + * Get the input stream. + * + * @param path the path to resource. + * @param classLoader the class loader. + * @return the input stream of the resource or null. + */ + @FromAnyThread + public static @Nullable InputStream getInputStream(@NotNull String path, @NotNull ClassLoader classLoader) { + return classLoader.getResourceAsStream(path); + } + + /** + * Convert unix time to string presentation. + * + * @param time the unix time. + * @return the string presentation. + */ + @FromAnyThread + public static @NotNull String timeFormat(long time) { + var format = LOCATE_DATE_FORMAT.get(); + return format.format(new Date(time)); + } + + /** + * Get the path to the file from the asset folder. + * + * @param assetFolder the asset folder. + * @param file the file. + * @return the relative path. + */ + @FromAnyThread + public static @NotNull Path getAssetFile(@NotNull Path assetFolder, @NotNull Path file) { + return assetFolder.relativize(file); + } + + /** + * Get a relative file to the file from the current asset folder. + * + * @param file the file. + * @return the relative file or null. + */ + @FromAnyThread + public static @Nullable Path getAssetFile(@NotNull Path file) { + try { + + return EditorConfig.getInstance() + .getCurrentAssetOpt() + .map(path -> path.relativize(file)) + .orElse(null); + + } catch (IllegalArgumentException e) { + LOGGER.warning("Can't create asset file of the " + file); + LOGGER.warning(e); + return null; + } + } + + /** + * Get an optional of a relative file to the file from the current asset folder. + * + * @param file the file. + * @return the optional of the relative file. + */ + @FromAnyThread + public static @NotNull Optional getAssetFileOpt(@NotNull Path file) { + return Optional.ofNullable(getAssetFile(file)); + } + + /** + * Get the path to the file from the current asset folder. + * + * @param file the file. + * @return the relative path. + */ + @FromAnyThread + public static @NotNull Path requireAssetFile(@NotNull Path file) { + return notNull(getAssetFile(file)); + } + + /** + * Get the absolute path to the file in the current asset. + * + * @param assetFile the file. + * @return the absolute path to the file. + */ + @FromAnyThread + public static @Nullable Path getRealFile(@NotNull Path assetFile) { + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + + if (currentAsset == null) { + return null; + } + + return currentAsset.resolve(assetFile); + } + + /** + * Get the absolute file by the asset key. + * + * @param assetKey the asset key. + * @return the absolute file. + */ + @FromAnyThread + public static @NotNull Path requireRealFile(@NotNull AssetKey assetKey) { + return requireRealFile(assetKey.getName()); + } + + /** + * Get the absolute file by the relative asset path. + * + * @param assetPath the relative path to the file. + * @return the absolute file. + */ + @FromAnyThread + public static @NotNull Path requireRealFile(@NotNull String assetPath) { + return EditorConfig.getInstance() + .getCurrentAssetOpt() + .filter(path -> StringUtils.isNotEmpty(assetPath)) + .map(path -> path.resolve(assetPath)) + .orElseThrow(() -> new IllegalStateException("Can't build a real file for the asset path " + assetPath)); + } + + /** + * Get the absolute file by the relative asset path. + * + * @param assetPath the relative path to the file. + * @return the absolute file. + */ + @FromAnyThread + public static @Nullable Path getRealFile(@NotNull String assetPath) { + + var editorConfig = EditorConfig.getInstance(); + var currentAsset = editorConfig.getCurrentAsset(); + + if (currentAsset == null || StringUtils.isEmpty(assetPath)) { + return null; + } + + return currentAsset.resolve(assetPath); + } + + /** + * To asset path string. + * + * @param path the path + * @return the valid asset path for the file. + */ + @FromAnyThread + public static @NotNull String toAssetPath(@NotNull Path path) { + + if (File.separatorChar == '/') { + return path.toString(); + } + + return path.toString().replace("\\", "/"); + } + + /** + * Handle exception. + * + * @param logger the logger. + * @param owner the owner. + * @param e the exception. + */ + @FromAnyThread + public static void handleException(@Nullable Logger logger, @Nullable Object owner, @NotNull Throwable e) { + handleException(logger, owner, e, null); + } + + /** + * Handle exception. + * + * @param logger the logger. + * @param owner the owner. + * @param e the exception. + * @param callback the callback. + */ + @FromAnyThread + public static void handleException( + @Nullable Logger logger, + @Nullable Object owner, + @NotNull Throwable e, + @Nullable Runnable callback + ) { + + if (logger == null) { + logger = LOGGER; + } + + if (owner == null) { + logger.warning(e); + } else { + logger.warning(owner, e); + } + + var executorManager = ExecutorManager.getInstance(); + executorManager.addFxTask(() -> { + + GAnalytics.sendException(e, false); + + var localizedMessage = e.getLocalizedMessage(); + var stackTrace = buildStackTrace(e); + + var alert = UiUtils.createErrorAlert(e, localizedMessage, stackTrace); + alert.show(); + alert.setWidth(500); + alert.setHeight(220); + + if (callback != null) { + alert.setOnHidden(event -> callback.run()); + } + }); + } + + /** + * Build the stack trace of the exception. + * + * @param exception the exception. + * @return the built stack trace. + */ + @FromAnyThread + public static String buildStackTrace(@NotNull Throwable exception) { + + var writer = new StringWriter(); + var printWriter = new PrintWriter(writer); + + exception.printStackTrace(printWriter); + + var stackTrace = writer.toString(); + + var level = 0; + + for (var cause = exception.getCause(); cause != null && level < 6; cause = cause.getCause(), level++) { + + writer = new StringWriter(); + printWriter = new PrintWriter(writer); + + cause.printStackTrace(printWriter); + + stackTrace += "\n caused by " + writer.toString(); + } + + return stackTrace; + } + + /** + * Open the file in an external editor. + * + * @param path the path + */ + @FromAnyThread + public static void openFileInExternalEditor(@NotNull Path path) { + + var platform = JmeSystem.getPlatform(); + var commands = new ArrayList(); + + if (platform == Platform.MacOSX64 || platform == Platform.MacOSX_PPC64) { + commands.add("open"); + } else if (platform == Platform.Windows32 || platform == Platform.Windows64) { + commands.add("cmd"); + commands.add("/c"); + commands.add("start"); + } else if (platform == Platform.Linux32|| platform == Platform.Linux64) { + commands.add("xdg-open"); + } + + if (commands.isEmpty()) { + return; + } + + String url; + try { + url = path.toUri().toURL().toString(); + } catch (MalformedURLException e) { + handleException(LOGGER, null, e); + return; + } + + commands.add(url); + + var processBuilder = new ProcessBuilder(); + processBuilder.command(commands); + + try { + processBuilder.start(); + } catch (IOException e) { + handleException(LOGGER, null, e); + } + } + + /** + * Open the file in a system explorer. + * + * @param path the path + */ + @FromAnyThread + public static void openFileInSystemExplorer(@NotNull Path path) { + + var platform = JmeSystem.getPlatform(); + var commands = new ArrayList(); + + if (platform == Platform.MacOSX64 || platform == Platform.MacOSX_PPC64) { + commands.add("open"); + commands.add("-R"); + } else if (platform == Platform.Windows32 || platform == Platform.Windows64) { + commands.add("explorer"); + commands.add("/select,"); + } else if (platform == Platform.Linux32 || platform == Platform.Linux64) { + if (isAppExists("nautilus -v")) { + commands.add("nautilus"); + } else if (isAppExists("dolphin -v")) { + commands.add("dolphin"); + commands.add("--select"); + } else { + commands.add("xdg-open"); + if (!Files.isDirectory(path)) { + path = path.getParent(); + } + } + } + + if (commands.isEmpty()) { + return; + } + + String url; + try { + url = path.toUri().toURL().toString(); + } catch (MalformedURLException e) { + handleException(LOGGER, null, e); + return; + } + + commands.add(url); + + var processBuilder = new ProcessBuilder(); + processBuilder.command(commands); + try { + processBuilder.start(); + } catch (IOException e) { + handleException(LOGGER, null, e); + } + } + + @FromAnyThread + private static boolean isAppExists(@NotNull String command) { + + var runtime = Runtime.getRuntime(); + int result; + try { + var exec = runtime.exec(command); + result = exec.waitFor(); + } catch (InterruptedException | IOException e) { + return false; + } + + return result >= 0; + } + + /** + * Convert the object to byte array. + * + * @param object the object + * @return the byte array. + */ + @FromAnyThread + public static @NotNull byte[] serialize(@NotNull Serializable object) { + + var bout = new ByteArrayOutputStream(); + + try (var out = new ObjectOutputStream(bout)) { + out.writeObject(object); + } catch (IOException e) { + LOGGER.warning(e); + } + + return bout.toByteArray(); + } + + /** + * Convert the byte array to object. + * + * @param the type parameter + * @param bytes the byte array. + * @return the result object. + */ + @FromAnyThread + public static @NotNull T deserialize(@NotNull byte[] bytes) { + + var bin = new ByteArrayInputStream(bytes); + + try (var in = new ExtObjectInputStream(bin)) { + return unsafeCast(in.readObject()); + } catch (ClassNotFoundException | IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Get an array of available enum values by an enum value. + * + * @param the type parameter + * @param value the enum value. + * @return the array of enum values. + */ + @FromAnyThread + public static > @NotNull E[] getAvailableValues(@NotNull E value) { + + var valueClass = value.getClass(); + + if (!valueClass.isEnum()) { + throw new RuntimeException("The class " + valueClass + " isn't enum."); + } + + var enumConstants = valueClass.getEnumConstants(); + + return unsafeCast(enumConstants); + } + + /** + * Try to create an user object using asset classpath and additional classpath. + * + * @param the type parameter + * @param owner the requester. + * @param className the classname. + * @param resultType the result type. + * @return the new instance or null. + */ + @FromAnyThread + public static @Nullable T tryToCreateUserObject( + @NotNull Object owner, + @NotNull String className, + @NotNull Class resultType + ) { + + var resourceManager = ResourceManager.getInstance(); + var classpathManager = ClasspathManager.getInstance(); + + Object newExample = null; + try { + newExample = ClassUtils.newInstance(className); + } catch (RuntimeException e) { + + var classLoaders = resourceManager.getClassLoaders(); + + for (var classLoader : classLoaders) { + try { + var targetClass = classLoader.loadClass(className); + newExample = ClassUtils.newInstance(targetClass); + } catch (ClassNotFoundException ex) { + LOGGER.warning(owner, e); + } + } + + var librariesLoader = classpathManager.getLibrariesLoader(); + + if (librariesLoader != null) { + try { + var targetClass = librariesLoader.loadClass(className); + newExample = ClassUtils.newInstance(targetClass); + } catch (final ClassNotFoundException ex) { + LOGGER.warning(owner, e); + } + } + } + + return cast(resultType, newExample); + } + + /** + * Get a default layer of the change consumer. + * + * @param consumer the change consumer. + * @return the default layer or null. + */ + @FromAnyThread + public static @Nullable SceneLayer getDefaultLayer(@NotNull ChangeConsumer consumer) { + + if (!(consumer instanceof SceneChangeConsumer)) { + return null; + } + + var sceneNode = ((SceneChangeConsumer) consumer).getCurrentModel(); + var layers = sceneNode.getLayers(); + + if (layers.isEmpty()) { + return null; + } + + return layers.get(0); + } + + /** + * Return true if the asset key is null or empty. + * + * @param assetKey the asset key. + * @return true if the asset key is null or empty. + */ + public static boolean isEmpty(@Nullable AssetKey assetKey) { + return assetKey == null || StringUtils.isEmpty(assetKey.getName()); + } + + /** + * Return the another string if the key is empty. + * + * @param assetKey the asset key. + * @return the another string if the key is empty. + */ + public static String ifEmpty(@Nullable AssetKey assetKey, @NotNull String another) { + return isEmpty(assetKey) ? another : assetKey.getName(); + } + + /** + * Open the asset resource in an editor. + * + * @param assetKey the asset key. + */ + @FromAnyThread + public static void openInEditor(@Nullable AssetKey assetKey) { + + if (assetKey == null || StringUtils.isEmpty(assetKey.getName())) { + LOGGER.warning("The asset key " + assetKey + " is empty or null."); + return; + } + + var assetPath = assetKey.getName(); + var realFile = requireRealFile(assetPath); + + if (!Files.exists(realFile)) { + LOGGER.warning("The file " + realFile + " is not exists."); + return; + } + + FxEventManager.getInstance() + .notify(new RequestedOpenFileEvent(realFile)); + } + + /** + * Get the list of files in the current dragboard. + * + * @param dragboard the current dragboard. + * @return the list of files. + */ + @FromAnyThread + public static @NotNull List getFiles(@NotNull Dragboard dragboard) { + List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); + return files == null ? Collections.emptyList() : files; + } + + /** + * Get an array of enum constants by the class. + * + * @param enumType the enum's class. + * @param the enum's type. + * @return the array of enum's constants. + */ + @FromAnyThread + public static T[] getEnumValues(@NotNull Class enumType) { + + if(!enumType.isEnum()) { + throw new IllegalArgumentException("The type " + enumType + " isn't a enum."); + } + + return unsafeCast(ENUM_VALUES_LOCAL.get() + .get(enumType, type -> (Enum[]) type.getEnumConstants())); + } + + /** + * Find a root key of the spatial. + * + * @param spatial the spatial. + * @return the root key or null. + */ + public static @Nullable String findRootKey(@Nullable Spatial spatial) { + + if(spatial == null) { + return null; + } + + return NodeUtils.findParentOpt(spatial, sp -> sp.getKey() != null) + .map(Spatial::getKey) + .map(AssetKey::getName) + .orElse(null); + } + + /** + * Lock the render phase in jME. + * + * @return the lock stamp. + */ + @FromAnyThread + public static long renderLock() { + return jmeApplication.asyncLock(); + } + + /** + * Unlock the render phase in jME. + * + * @param stamp the lock stamp. + */ + @FromAnyThread + public static void renderUnlock(long stamp) { + jmeApplication.asyncUnlock(stamp); + } + + /** + * Build an asset key for the real file. + * + * @param realFile the real file. + * @param constructor the asset key's constructor. + * @param the asset key's type. + * @return the asset key. + */ + public static > @NotNull T realFileToKey( + @NotNull Path realFile, + @NotNull Function constructor + ) { + return getAssetFileOpt(realFile) + .map(EditorUtils::toAssetPath) + .map(constructor) + .orElseThrow(() -> new RuntimeException("Can't build an asset key for the file " + realFile)); + } + + /** + * Clear the asset cache. + */ + @JmeThread + public static void clearAssetCache() { + getAssetManager().clearCache(); + } +} diff --git a/src/main/java/com/ss/editor/util/ExtObjectInputStream.java b/src/main/java/com/ss/builder/util/ExtObjectInputStream.java similarity index 89% rename from src/main/java/com/ss/editor/util/ExtObjectInputStream.java rename to src/main/java/com/ss/builder/util/ExtObjectInputStream.java index b82c1a3b..90a408ae 100644 --- a/src/main/java/com/ss/editor/util/ExtObjectInputStream.java +++ b/src/main/java/com/ss/builder/util/ExtObjectInputStream.java @@ -1,6 +1,7 @@ -package com.ss.editor.util; +package com.ss.builder.util; -import com.ss.editor.manager.PluginManager; +import com.ss.builder.manager.PluginManager; +import com.ss.builder.manager.PluginManager; import com.ss.rlib.common.util.ref.ReferenceFactory; import com.ss.rlib.common.util.ref.ReferenceType; import org.jetbrains.annotations.NotNull; @@ -32,7 +33,7 @@ protected Class resolveClass(@NotNull ObjectStreamClass desc) throws IOExcept try (var ref = ReferenceFactory.takeFromTLPool(ReferenceType.OBJECT)) { var pluginManager = PluginManager.getInstance(); - pluginManager.handlePlugins(plugin -> { + pluginManager.handlePluginsNow(plugin -> { if (ref.getObject() != null) { return; diff --git a/src/main/java/com/ss/editor/util/GeomUtils.java b/src/main/java/com/ss/builder/util/GeomUtils.java similarity index 83% rename from src/main/java/com/ss/editor/util/GeomUtils.java rename to src/main/java/com/ss/builder/util/GeomUtils.java index 448c369a..97a4af45 100644 --- a/src/main/java/com/ss/editor/util/GeomUtils.java +++ b/src/main/java/com/ss/builder/util/GeomUtils.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.collision.CollisionResult; import com.jme3.collision.CollisionResults; @@ -10,13 +10,17 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +import static java.lang.Math.acos; +import static java.lang.Math.toDegrees; + /** * The class with utility methods for working with geometry. * @@ -24,6 +28,81 @@ */ public class GeomUtils { + /** + * Calculate new point from first point and using second point like a direction. + * + * @param first the first point. + * @param second the second point. + * @param store the container of the result. + * @param length the distance. + */ + @FromAnyThread + public static void movePoint( + @NotNull Vector3f first, + @NotNull Vector3f second, + @NotNull Vector3f store, + int length + ) { + store.x = first.x + (second.x - first.x) * length; + store.y = first.y + (second.y - first.y) * length; + store.z = first.z + (second.z - first.z) * length; + } + + /** + * Check visibility the position on the screen. + * + * @param position the position for checking. + * @param camera the camera of the screen. + * @return true of we can see the position on the screen. + */ + @FromAnyThread + public static boolean isVisibleOnScreen(@NotNull Vector3f position, @NotNull Camera camera) { + + var maxHeight = camera.getHeight(); + var maxWidth = camera.getWidth(); + + var isBottom = position.getY() < 0; + var isTop = position.getY() > maxHeight; + var isLeft = position.getX() < 0; + var isRight = position.getX() > maxWidth; + + return !isBottom && !isLeft && !isTop && !isRight && position.getZ() < 1F; + } + + /** + * Get the angle between these points. + * + * @param center the center. + * @param first the first point. + * @param second the second point. + * @return the angle between these points. + */ + @FromAnyThread + public static float getAngle( + @NotNull Vector2f center, + @NotNull Vector2f first, + @NotNull Vector2f second + ) { + + var x = center.getX(); + var y = center.getY(); + + var ax = first.getX() - x; + var ay = first.getY() - y; + var bx = second.getX() - x; + var by = second.getY() - y; + + var delta = (float) ((ax * bx + ay * by) / Math.sqrt((ax * ax + ay * ay) * (bx * bx + by * by))); + + if (delta > 1.0) { + return 0.0F; + } else if (delta < -1.0) { + return 180.0F; + } + + return (float) toDegrees(acos(delta)); + } + /** * Get the UP vector from the rotation. * @@ -223,7 +302,7 @@ public static boolean canAttach(@NotNull Node node, @NotNull Spatial spatial, bo */ @FromAnyThread public static @Nullable Vector3f getContactPointFromCursor(@NotNull Spatial spatial, @NotNull Camera camera) { - var inputManager = EditorUtil.getInputManager(); + var inputManager = EditorUtils.getInputManager(); var cursor = inputManager.getCursorPosition(); return getContactPointFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); } @@ -237,7 +316,7 @@ public static boolean canAttach(@NotNull Node node, @NotNull Spatial spatial, bo */ @FromAnyThread public static @Nullable CollisionResult getCollisionFromCursor(@NotNull Spatial spatial, @NotNull Camera camera) { - var inputManager = EditorUtil.getInputManager(); + var inputManager = EditorUtils.getInputManager(); var cursor = inputManager.getCursorPosition(); return getCollisionFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); } @@ -251,7 +330,7 @@ public static boolean canAttach(@NotNull Node node, @NotNull Spatial spatial, bo */ @FromAnyThread public static @NotNull CollisionResults getCollisionsFromCursor(@NotNull Spatial spatial, @NotNull Camera camera) { - var inputManager = EditorUtil.getInputManager(); + var inputManager = EditorUtils.getInputManager(); var cursor = inputManager.getCursorPosition(); return getCollisionsFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); } @@ -305,7 +384,7 @@ public static boolean canAttach(@NotNull Node node, @NotNull Spatial spatial, bo */ @FromAnyThread public static @Nullable Geometry getGeometryFromCursor(@NotNull Spatial spatial, @NotNull Camera camera) { - var inputManager = EditorUtil.getInputManager(); + var inputManager = EditorUtils.getInputManager(); var cursor = inputManager.getCursorPosition(); return getGeometryFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); } diff --git a/src/main/java/com/ss/editor/util/GlslType.java b/src/main/java/com/ss/builder/util/GlslType.java similarity index 95% rename from src/main/java/com/ss/editor/util/GlslType.java rename to src/main/java/com/ss/builder/util/GlslType.java index 793c1056..125752b5 100644 --- a/src/main/java/com/ss/editor/util/GlslType.java +++ b/src/main/java/com/ss/builder/util/GlslType.java @@ -1,7 +1,8 @@ -package com.ss.editor.util; +package com.ss.builder.util; import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.rlib.common.util.dictionary.DictionaryFactory; import com.ss.rlib.common.util.dictionary.ObjectDictionary; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/builder/util/JmbEditorEnvoriment.java b/src/main/java/com/ss/builder/util/JmbEditorEnvoriment.java new file mode 100644 index 00000000..5aa3d70b --- /dev/null +++ b/src/main/java/com/ss/builder/util/JmbEditorEnvoriment.java @@ -0,0 +1,38 @@ +package com.ss.builder.util; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.util.UiUtils; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.editor.extension.integration.EditorEnvironment; +import com.ss.builder.manager.ExecutorManager; +import com.ss.builder.fx.util.UiUtils; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link EditorEnvironment}. + * + * @author JavaSaBr + */ +public class JmbEditorEnvoriment implements EditorEnvironment { + + private static final JmbEditorEnvoriment INSTANCE = new JmbEditorEnvoriment(); + + public static @NotNull JmbEditorEnvoriment getInstance() { + return INSTANCE; + } + + @Override + @FromAnyThread + public void notifyStartLoading() { + ExecutorManager.getInstance() + .addFxTask(UiUtils::incrementLoading); + } + + @Override + @FromAnyThread + public void notifyEndLoading() { + ExecutorManager.getInstance() + .addFxTask(UiUtils::decrementLoading); + } +} diff --git a/src/main/java/com/ss/builder/util/JmeUtils.java b/src/main/java/com/ss/builder/util/JmeUtils.java new file mode 100644 index 00000000..5f5204b8 --- /dev/null +++ b/src/main/java/com/ss/builder/util/JmeUtils.java @@ -0,0 +1,90 @@ +package com.ss.builder.util; + +import com.jme3.asset.AssetManager; +import com.jme3.input.InputManager; +import com.jme3.input.controls.Trigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import org.jetbrains.annotations.NotNull; + +/** + * The class with utility methods for the jME things. + * + * @author JavaSaBr + */ +public class JmeUtils { + + /** + * Add mapping to the input manager. + * + * @param inputManager the input manager. + * @param name the mapping name. + * @param trigger the trigger. + */ + @JmeThread + public static void addMapping(@NotNull InputManager inputManager, @NotNull String name, @NotNull Trigger trigger) { + if (!inputManager.hasMapping(name)) { + inputManager.addMapping(name, trigger); + } + } + + /** + * Add mapping to the input manager. + * + * @param inputManager the input manager. + * @param name the mapping name. + * @param triggers the triggers. + */ + @JmeThread + public static void addMapping( + @NotNull InputManager inputManager, + @NotNull String name, + @NotNull Trigger... triggers + ) { + if (!inputManager.hasMapping(name)) { + inputManager.addMapping(name, triggers); + } + } + + /** + * Create a material with the color. + */ + @FromAnyThread + public static @NotNull Material coloredWireframeMaterial( + @NotNull ColorRGBA color, + @NotNull AssetManager assetManagers + ) { + + var material = new Material(assetManagers, "Common/MatDefs/Misc/Unshaded.j3md"); + material.getAdditionalRenderState().setWireframe(true); + material.setColor("Color", color); + + return material; + } + + /** + * Get position os the location on the camera. + * + * @param location the location. + * @param camera the camera. + * @return the position on the camera. + */ + @JmeThread + public static @NotNull Vector3f getPositionOnCamera(@NotNull Vector3f location, @NotNull Camera camera) { + + var local = LocalObjects.get(); + + var cameraLocation = camera.getLocation(); + var resultPosition = location.subtract(cameraLocation, local.nextVector()) + .normalizeLocal() + .multLocal(camera.getFrustumNear() + 0.5f); + + return cameraLocation.add(resultPosition, local.nextVector()); + } +} diff --git a/src/main/java/com/ss/editor/util/LocalObjects.java b/src/main/java/com/ss/builder/util/LocalObjects.java similarity index 90% rename from src/main/java/com/ss/editor/util/LocalObjects.java rename to src/main/java/com/ss/builder/util/LocalObjects.java index a122ec89..8c11ff0e 100644 --- a/src/main/java/com/ss/editor/util/LocalObjects.java +++ b/src/main/java/com/ss/builder/util/LocalObjects.java @@ -1,11 +1,12 @@ -package com.ss.editor.util; +package com.ss.builder.util; -import static java.lang.Thread.currentThread; import com.jme3.collision.CollisionResults; import com.jme3.math.*; import com.jme3.scene.Spatial; -import com.ss.editor.EditorThread; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.EditorThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.EditorThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.rlib.common.util.CycleBuffer; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -25,16 +26,11 @@ public class LocalObjects { private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(LocalObjects::new); - /** - * Get the local objects. - * - * @return the local objects - */ public static @NotNull LocalObjects get() { - final Thread currentThread = currentThread(); + var currentThread = Thread.currentThread(); if (currentThread instanceof EditorThread) { - ((EditorThread) currentThread).getLocal(); + return ((EditorThread) currentThread).getLocal(); } return THREAD_LOCAL.get(); @@ -94,6 +90,12 @@ public class LocalObjects { @NotNull private final CycleBuffer matrixFloatBuffer; + /** + * The buffer of 3 float arrays. + */ + @NotNull + private final CycleBuffer array3fBuffer; + /** * The buffer of object arrays. */ @@ -115,6 +117,7 @@ public LocalObjects() { this.rayBuffer = new CycleBuffer<>(Ray.class, SIZE, Ray::new); this.matrix3fBuffer = new CycleBuffer<>(Matrix3f.class, SIZE, Matrix3f::new); this.matrixFloatBuffer = new CycleBuffer<>(float[].class, SIZE, () -> new float[16]); + this.array3fBuffer = new CycleBuffer<>(float[].class, SIZE, () -> new float[3]); this.colorBuffer = new CycleBuffer<>(ColorRGBA.class, SIZE, ColorRGBA::new); this.objectArrayBuffer = new CycleBuffer<>(Array.class, SIZE, () -> ArrayFactory.newArray(Object.class), Collection::clear); this.spatialArrayBuffer = new CycleBuffer<>(Array.class, SIZE, () -> ArrayFactory.newArray(Spatial.class), Collection::clear); @@ -162,6 +165,16 @@ public LocalObjects() { return matrixFloatBuffer.next(); } + /** + * Get the next 3 float array. + * + * @return the next 3 float array. + */ + @FromAnyThread + public @NotNull float[] nextArray3f() { + return array3fBuffer.next(); + } + /** * Get the next free ray. * diff --git a/src/main/java/com/ss/editor/util/MaterialSerializer.java b/src/main/java/com/ss/builder/util/MaterialSerializer.java similarity index 98% rename from src/main/java/com/ss/editor/util/MaterialSerializer.java rename to src/main/java/com/ss/builder/util/MaterialSerializer.java index 2c066f0d..b11e9013 100644 --- a/src/main/java/com/ss/editor/util/MaterialSerializer.java +++ b/src/main/java/com/ss/builder/util/MaterialSerializer.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.asset.TextureKey; import com.jme3.material.MatParam; @@ -12,7 +12,8 @@ import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; import com.jme3.texture.TextureCubeMap; -import com.ss.editor.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.FromAnyThread; import com.ss.rlib.common.util.StringUtils; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/util/MaterialUtils.java b/src/main/java/com/ss/builder/util/MaterialUtils.java similarity index 94% rename from src/main/java/com/ss/editor/util/MaterialUtils.java rename to src/main/java/com/ss/builder/util/MaterialUtils.java index 4983c990..e2950249 100644 --- a/src/main/java/com/ss/editor/util/MaterialUtils.java +++ b/src/main/java/com/ss/builder/util/MaterialUtils.java @@ -1,6 +1,6 @@ -package com.ss.editor.util; +package com.ss.builder.util; -import static com.ss.editor.util.EditorUtil.*; +import static com.ss.builder.util.EditorUtils.*; import static com.ss.rlib.common.util.ObjectUtils.notNull; import static com.ss.rlib.common.util.array.ArrayFactory.toArray; import static java.nio.file.StandardOpenOption.*; @@ -13,9 +13,12 @@ import com.jme3.scene.Spatial; import com.jme3.shader.VarType; import com.jme3.texture.Texture; -import com.ss.editor.FileExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.FileExtensions; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; import com.ss.rlib.common.util.FileUtils; import com.ss.rlib.common.util.StringUtils; import jme3tools.converters.ImageToAwt; @@ -122,7 +125,7 @@ public static int getPossibleTextureType(@NotNull String textureName) { @JmeThread public static @Nullable Material updateMaterialIdNeed(@NotNull Path file, @NotNull Material material) { - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); boolean needToReload = false; String textureKey = null; @@ -179,8 +182,8 @@ public static int getPossibleTextureType(@NotNull String textureName) { private static boolean containsShader(@NotNull Material material, @NotNull Path file) { var materialDef = material.getMaterialDef(); - var assetFile = notNull(getAssetFile(file), "Can't get an asset file."); - var assetPath = toAssetPath(assetFile); + var assetFile = notNull(EditorUtils.getAssetFile(file), "Can't get an asset file."); + var assetPath = EditorUtils.toAssetPath(assetFile); return containsShader(materialDef, assetPath); } @@ -195,8 +198,8 @@ private static boolean containsShader(@NotNull Material material, @NotNull Path @FromAnyThread private static @Nullable String containsTexture(@NotNull Material material, @NotNull Path file) { - var assetFile = notNull(getAssetFile(file), "Can't get an asset file."); - var assetPath = toAssetPath(assetFile); + var assetFile = notNull(EditorUtils.getAssetFile(file), "Can't get an asset file."); + var assetPath = EditorUtils.toAssetPath(assetFile); return containsTexture(material, assetPath) ? assetPath : null; } @@ -289,7 +292,7 @@ public static boolean isTextureFile(@NotNull Path path) { @JmeThread private static void refreshTextures(@NotNull Material material, @NotNull String textureKey) { - var assetManager = EditorUtil.getAssetManager(); + var assetManager = EditorUtils.getAssetManager(); material.getParams().forEach(matParam -> { @@ -423,7 +426,7 @@ private static void saveIfNeedTexture(@NotNull Texture texture) { } var key = texture.getKey(); - var file = notNull(getRealFile(key.getName())); + var file = notNull(EditorUtils.getRealFile(key.getName())); var bufferedImage = ImageToAwt.convert(image, false, true, 0); try (var out = Files.newOutputStream(file, WRITE, TRUNCATE_EXISTING, CREATE)) { diff --git a/src/main/java/com/ss/editor/util/NodeUtils.java b/src/main/java/com/ss/builder/util/NodeUtils.java similarity index 84% rename from src/main/java/com/ss/editor/util/NodeUtils.java rename to src/main/java/com/ss/builder/util/NodeUtils.java index eec2cf11..54af2cc8 100644 --- a/src/main/java/com/ss/editor/util/NodeUtils.java +++ b/src/main/java/com/ss/builder/util/NodeUtils.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import static com.ss.rlib.common.util.ClassUtils.unsafeCast; import com.jme3.audio.AudioNode; @@ -8,8 +8,10 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.Spatial.DFSMode; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.annotation.JmeThread; import com.ss.rlib.common.util.StringUtils; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; @@ -19,6 +21,7 @@ import java.lang.reflect.Field; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -276,7 +279,20 @@ public class NodeUtils { } /** - * Collect all geometries from the asset path. + * Collect all geometries with materials from the asset path. + * + * @param spatial the spatial. + * @param assetPath the asset path. + */ + @FromAnyThread + public static Array getGeometriesWithMaterial(@NotNull Spatial spatial, @NotNull String assetPath) { + var container = Array.ofType(Geometry.class); + addGeometryWithMaterial(spatial, container, assetPath); + return container; + } + + /** + * Collect all geometries with materials from the asset path. * * @param spatial the spatial. * @param container the container. @@ -366,6 +382,28 @@ public static void visitGeometry(@NotNull Spatial spatial, @NotNull Consumer the mapper's result type. + */ + @FromAnyThread + public static void visitGeometry( + @NotNull Spatial spatial, + @NotNull Function<@NotNull Geometry, @NotNull R> mapper, + @NotNull Consumer<@NotNull R> consumer + ) { + + spatial.depthFirstTraversal(sp -> { + if (spatial instanceof Geometry) { + consumer.accept(mapper.apply((Geometry) sp)); + } + }, DFSMode.PRE_ORDER); + } + /** * Visit all spatial. * @@ -449,7 +487,7 @@ public static void visitSpatial( */ @FromAnyThread public static @NotNull Array getGeometries(@NotNull Spatial spatial) { - var result = ArrayFactory.newArray(Geometry.class); + var result = ArrayFactory.newArray(Geometry.class); addGeometry(spatial, result); return result; } @@ -477,6 +515,23 @@ public static void addGeometry(@NotNull Spatial spatial, @NotNull Array getAllLights(@NotNull Spatial spatial) { + + var lights = Array.ofType(Light.class); + + spatial.depthFirstTraversal(sp -> + sp.getLocalLightList().forEach(lights::add)); + + return lights; + } + /** * Collect all lights. * @@ -484,6 +539,7 @@ public static void addGeometry(@NotNull Spatial spatial, @NotNull Array container) { var lightList = spatial.getLocalLightList(); @@ -500,6 +556,26 @@ public static void addLight(@NotNull Spatial spatial, @NotNull Array cont } } + /** + * Collect all audio nodes. + * + * @param spatial the spatial. + * @return the list of all found audio nodes. + */ + @FromAnyThread + public static @NotNull Array getAllAudioNodes(@NotNull Spatial spatial) { + + var audioNodes = Array.ofType(AudioNode.class); + + spatial.depthFirstTraversal(sp -> { + if (sp instanceof AudioNode) { + audioNodes.add((AudioNode) sp); + } + }); + + return audioNodes; + } + /** * Collect all audio nodes. * @@ -507,6 +583,7 @@ public static void addLight(@NotNull Spatial spatial, @NotNull Array cont * @param container the container. */ @FromAnyThread + @Deprecated(forRemoval = true) public static void addAudioNodes(@NotNull Spatial spatial, @NotNull Array container) { if (!(spatial instanceof Node)) { @@ -532,7 +609,7 @@ public static void addAudioNodes(@NotNull Spatial spatial, @NotNull Array children(@NotNull Spatial spatial) { - var result = ArrayFactory.newArray(Spatial.class); + var result = ArrayFactory.newArray(Spatial.class); visitSpatial(spatial, sp -> { result.add(sp); diff --git a/src/main/java/com/ss/editor/util/OpenGLVersion.java b/src/main/java/com/ss/builder/util/OpenGLVersion.java similarity index 98% rename from src/main/java/com/ss/editor/util/OpenGLVersion.java rename to src/main/java/com/ss/builder/util/OpenGLVersion.java index b3f126b7..102e1e7b 100644 --- a/src/main/java/com/ss/editor/util/OpenGLVersion.java +++ b/src/main/java/com/ss/builder/util/OpenGLVersion.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.system.AppSettings; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/util/PaintingUtils.java b/src/main/java/com/ss/builder/util/PaintingUtils.java similarity index 96% rename from src/main/java/com/ss/editor/util/PaintingUtils.java rename to src/main/java/com/ss/builder/util/PaintingUtils.java index 70c4e44c..cf9785c0 100644 --- a/src/main/java/com/ss/editor/util/PaintingUtils.java +++ b/src/main/java/com/ss/builder/util/PaintingUtils.java @@ -1,11 +1,11 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Sphere; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.control.painting.PaintingControl; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.jme.control.painting.PaintingControl; import com.ss.rlib.common.geom.util.CoordsUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/util/ReusableCollisionResults.java b/src/main/java/com/ss/builder/util/ReusableCollisionResults.java similarity index 93% rename from src/main/java/com/ss/editor/util/ReusableCollisionResults.java rename to src/main/java/com/ss/builder/util/ReusableCollisionResults.java index 42b79a75..20f17c67 100644 --- a/src/main/java/com/ss/editor/util/ReusableCollisionResults.java +++ b/src/main/java/com/ss/builder/util/ReusableCollisionResults.java @@ -1,8 +1,9 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.collision.CollisionResult; import com.jme3.collision.CollisionResults; -import com.ss.editor.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; +import com.ss.builder.annotation.JmeThread; import com.ss.rlib.common.util.array.Array; import com.ss.rlib.common.util.array.ArrayFactory; import com.ss.rlib.common.util.pools.Reusable; diff --git a/src/main/java/com/ss/editor/util/SimpleFileVisitor.java b/src/main/java/com/ss/builder/util/SimpleFileVisitor.java similarity index 97% rename from src/main/java/com/ss/editor/util/SimpleFileVisitor.java rename to src/main/java/com/ss/builder/util/SimpleFileVisitor.java index efaefd18..56579d80 100644 --- a/src/main/java/com/ss/editor/util/SimpleFileVisitor.java +++ b/src/main/java/com/ss/builder/util/SimpleFileVisitor.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/ss/editor/util/SimpleFolderVisitor.java b/src/main/java/com/ss/builder/util/SimpleFolderVisitor.java similarity index 96% rename from src/main/java/com/ss/editor/util/SimpleFolderVisitor.java rename to src/main/java/com/ss/builder/util/SimpleFolderVisitor.java index c55e8466..abe76fba 100644 --- a/src/main/java/com/ss/editor/util/SimpleFolderVisitor.java +++ b/src/main/java/com/ss/builder/util/SimpleFolderVisitor.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/ss/editor/util/TangentGenerator.java b/src/main/java/com/ss/builder/util/TangentGenerator.java similarity index 92% rename from src/main/java/com/ss/editor/util/TangentGenerator.java rename to src/main/java/com/ss/builder/util/TangentGenerator.java index 5340bbd2..62612959 100644 --- a/src/main/java/com/ss/editor/util/TangentGenerator.java +++ b/src/main/java/com/ss/builder/util/TangentGenerator.java @@ -1,4 +1,4 @@ -package com.ss.editor.util; +package com.ss.builder.util; import com.jme3.scene.Spatial; import com.jme3.scene.VertexBuffer.Type; @@ -38,7 +38,7 @@ public static void useStandardGenerator(@NotNull Spatial spatial, boolean splitM }); } catch (Exception e) { - EditorUtil.handleException(LOGGER, null, e); + EditorUtils.handleException(LOGGER, null, e); } } @@ -61,7 +61,7 @@ public static void useMikktspaceGenerator(@NotNull Spatial spatial) { }); } catch (Exception e) { - EditorUtil.handleException(LOGGER, null, e); + EditorUtils.handleException(LOGGER, null, e); } } } diff --git a/src/main/java/com/ss/builder/util/TimeTracker.java b/src/main/java/com/ss/builder/util/TimeTracker.java new file mode 100644 index 00000000..e8458014 --- /dev/null +++ b/src/main/java/com/ss/builder/util/TimeTracker.java @@ -0,0 +1,83 @@ +package com.ss.builder.util; + +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.Config; +import com.ss.builder.annotation.FromAnyThread; +import com.ss.builder.config.Config; +import com.ss.rlib.common.logging.Logger; +import com.ss.rlib.common.logging.LoggerLevel; +import com.ss.rlib.common.logging.LoggerManager; +import com.ss.rlib.common.util.ArrayUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +/** + * The time tracker. + * + * @author JavaSaBr + */ +public class TimeTracker { + + private static final Logger LOGGER = LoggerManager.getLogger(TimeTracker.class); + + static { + LOGGER.setEnabled(LoggerLevel.INFO, true); + } + + public static final int STARTPUL_LEVEL_1 = 0; + public static final int STARTPUL_LEVEL_2 = 1; + public static final int STARTPUL_LEVEL_3 = 2; + public static final int STARTPUL_LEVEL_4 = 3; + public static final int STARTPUL_LEVEL_5 = 4; + public static final int STARTPUL_LEVEL_6 = 5; + + private static final TimeTracker[] STARTUP_TRACKERS = new TimeTracker[10]; + + static { + ArrayUtils.fill(STARTUP_TRACKERS, () -> new TimeTracker(() -> Config.DEV_DEBUG_STARTUP)); + } + + @FromAnyThread + public static @NotNull TimeTracker getStartupTracker() { + return getStartupTracker(0); + } + + @FromAnyThread + public static @NotNull TimeTracker getStartupTracker(int level) { + return STARTUP_TRACKERS[level]; + } + + @NotNull + private final BooleanSupplier condition; + + private volatile long time; + + private TimeTracker(@NotNull BooleanSupplier condition) { + this.condition = condition; + } + + @FromAnyThread + public void start() { + if (condition.getAsBoolean()) { + time = System.currentTimeMillis(); + } + } + + @FromAnyThread + public void finish(@NotNull Supplier messageFactory) { + if (condition.getAsBoolean()) { + LOGGER.info(messageFactory.get() + ": " + (System.currentTimeMillis() - time) + "ms."); + } + } + + @FromAnyThread + public void finishAndStart(@NotNull Supplier messageFactory) { + if (condition.getAsBoolean()) { + var currentTime = System.currentTimeMillis(); + LOGGER.info(messageFactory.get() + ": " + (currentTime - time) + "ms."); + time = currentTime; + } + } +} diff --git a/src/main/java/com/ss/editor/util/svg/SvgImageLoader.java b/src/main/java/com/ss/builder/util/svg/SvgImageLoader.java similarity index 98% rename from src/main/java/com/ss/editor/util/svg/SvgImageLoader.java rename to src/main/java/com/ss/builder/util/svg/SvgImageLoader.java index b77e14e7..69a571e6 100644 --- a/src/main/java/com/ss/editor/util/svg/SvgImageLoader.java +++ b/src/main/java/com/ss/builder/util/svg/SvgImageLoader.java @@ -1,8 +1,8 @@ -package com.ss.editor.util.svg; +package com.ss.builder.util.svg; import static org.apache.batik.transcoder.SVGAbstractTranscoder.KEY_HEIGHT; import static org.apache.batik.transcoder.SVGAbstractTranscoder.KEY_WIDTH; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.sun.javafx.iio.ImageFrame; import com.sun.javafx.iio.ImageStorage.ImageType; import de.codecentric.centerdevice.javafxsvg.BufferedImageTranscoder; diff --git a/src/main/java/com/ss/editor/util/svg/SvgImageLoaderFactory.java b/src/main/java/com/ss/builder/util/svg/SvgImageLoaderFactory.java similarity index 88% rename from src/main/java/com/ss/editor/util/svg/SvgImageLoaderFactory.java rename to src/main/java/com/ss/builder/util/svg/SvgImageLoaderFactory.java index 4d66215e..a4d2f7cb 100644 --- a/src/main/java/com/ss/editor/util/svg/SvgImageLoaderFactory.java +++ b/src/main/java/com/ss/builder/util/svg/SvgImageLoaderFactory.java @@ -1,6 +1,7 @@ -package com.ss.editor.util.svg; +package com.ss.builder.util.svg; -import com.ss.editor.annotation.FxThread; +import com.ss.builder.annotation.FxThread; +import com.ss.builder.annotation.FxThread; import com.sun.javafx.iio.ImageFormatDescription; import com.sun.javafx.iio.ImageLoader; import com.sun.javafx.iio.ImageLoaderFactory; @@ -8,7 +9,6 @@ import de.codecentric.centerdevice.javafxsvg.SvgDescriptor; import org.jetbrains.annotations.NotNull; -import java.io.IOException; import java.io.InputStream; /** @@ -36,7 +36,7 @@ public ImageFormatDescription getFormatDescription() { @Override @FxThread - public ImageLoader createImageLoader(@NotNull InputStream input) throws IOException { + public ImageLoader createImageLoader(@NotNull InputStream input) { return new SvgImageLoader(input); } } diff --git a/src/main/java/com/ss/editor/JfxApplication.java b/src/main/java/com/ss/editor/JfxApplication.java deleted file mode 100644 index d06ee5f7..00000000 --- a/src/main/java/com/ss/editor/JfxApplication.java +++ /dev/null @@ -1,521 +0,0 @@ -package com.ss.editor; - -import static com.jme3.jfx.injfx.JmeToJfxIntegrator.bind; -import static com.jme3.jfx.injfx.processor.FrameTransferSceneProcessor.TransferMode.ON_CHANGES; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_OPEN_GL; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.Utils.run; -import static java.nio.file.Files.createDirectories; -import static java.nio.file.Files.newOutputStream; -import com.jme3.jfx.injfx.JmeToJfxApplication; -import com.jme3.jfx.injfx.processor.FrameTransferSceneProcessor; -import com.jme3.util.LWJGLBufferAllocator; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.CommandLineConfig; -import com.ss.editor.config.Config; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.executor.impl.JmeThreadExecutor; -import com.ss.editor.file.converter.FileConverterRegistry; -import com.ss.editor.manager.*; -import com.ss.editor.plugin.api.settings.SettingsProviderRegistry; -import com.ss.editor.task.CheckNewVersionTask; -import com.ss.editor.ui.builder.EditorFxSceneBuilder; -import com.ss.editor.ui.component.asset.tree.AssetTreeContextMenuFillerRegistry; -import com.ss.editor.ui.component.creator.FileCreatorRegistry; -import com.ss.editor.ui.component.editor.EditorRegistry; -import com.ss.editor.ui.component.log.LogView; -import com.ss.editor.ui.control.property.builder.PropertyBuilderRegistry; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactoryRegistry; -import com.ss.editor.ui.css.CssRegistry; -import com.ss.editor.ui.dialog.ConfirmDialog; -import com.ss.editor.ui.preview.FilePreviewFactoryRegistry; -import com.ss.editor.ui.scene.EditorFxScene; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.OpenGLVersion; -import com.ss.editor.util.svg.SvgImageLoaderFactory; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerLevel; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.logging.impl.FolderFileListener; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.array.ConcurrentArray; -import javafx.application.Application; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.scene.control.ComboBoxBase; -import javafx.scene.image.Image; -import javafx.stage.Stage; -import javafx.stage.StageStyle; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.Configuration; - -import javax.imageio.ImageIO; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Level; - -/** - * The starter of the JavaFX application. - * - * @author JavaSaBr - */ -public class JfxApplication extends Application { - - private static final Logger LOGGER = LoggerManager.getLogger(JfxApplication.class); - - @Nullable - private static JfxApplication instance; - - /** - * It's an internal method. - * - * @see EditorUtil - */ - @Deprecated - @FromAnyThread - public static @NotNull JfxApplication getInstance() { - return notNull(instance); - } - - /** - * The start application method. - */ - public static void main(@NotNull String[] args) { - configureLogger(); - - // need to disable to work on macos - Configuration.GLFW_CHECK_THREAD0.set(false); - // use jemalloc - Configuration.MEMORY_ALLOCATOR.set("jemalloc"); - - // JavaFX - System.setProperty("prism.lcdtext", "false"); - //System.setProperty("prism.text", "t2k"); - - var editorConfig = EditorConfig.getInstance(); - var openGLVersion = editorConfig.getEnum(PREF_OPEN_GL, PREF_DEFAULT_OPEN_GL); - - // set a render if it isn't override - if(System.getProperty("jfx.background.render") == null) { - System.setProperty("jfx.background.render", openGLVersion.getRender()); - } - - System.setProperty(LWJGLBufferAllocator.PROPERTY_CONCURRENT_BUFFER_ALLOCATOR, "true"); - - CommandLineConfig.args(args); - - JmeToJfxApplication application; - try { - application = JmeApplication.prepareToStart(); - } catch (final Throwable e) { - printError(e); - System.exit(-1); - return; - } - - InitializeManager.register(ClasspathManager.class); - InitializeManager.register(ResourceManager.class); - InitializeManager.register(JavaFxImageManager.class); - InitializeManager.register(FileIconManager.class); - InitializeManager.register(WorkspaceManager.class); - InitializeManager.register(PluginManager.class); - InitializeManager.register(RemoteControlManager.class); - InitializeManager.initialize(); - - new EditorThread(new ThreadGroup("LWJGL"), - () -> startJmeApplication(application), "LWJGL Render").start(); - } - - @FxThread - private static void configureLogger() { - - // disable the standard logger - if (!Config.DEV_DEBUG) { - java.util.logging.Logger.getLogger("").setLevel(Level.WARNING); - } else { - java.util.logging.Logger.getLogger("").setLevel(Level.ALL); - } - - // configure our logger - LoggerLevel.DEBUG.setEnabled(Config.DEV_DEBUG); - LoggerLevel.INFO.setEnabled(true); - LoggerLevel.ERROR.setEnabled(true); - LoggerLevel.WARNING.setEnabled(true); - - var logFolder = Config.getFolderForLog(); - - if (!Files.exists(logFolder)) { - run(() -> createDirectories(logFolder)); - } - - if (!LoggerLevel.DEBUG.isEnabled()) { - LoggerManager.addListener(new FolderFileListener(logFolder)); - } - } - - /** - * Start the new jME application. - * - * @param application the new jME application. - */ - @JmeThread - private static void startJmeApplication(@NotNull JmeToJfxApplication application) { - - var initializationManager = InitializationManager.getInstance(); - initializationManager.onBeforeCreateJmeContext(); - - application.start(); - - var context = application.getContext(); - var renderer = context.getRenderer(); - - if (renderer == null) { - var editorConfig = EditorConfig.getInstance(); - editorConfig.set(PREF_OPEN_GL, OpenGLVersion.GL_20); - editorConfig.save(); - } - } - - /** - * Create a new focus listener. - * - * @return the new focus listener. - */ - @FxThread - private static @NotNull ChangeListener makeFocusedListener() { - return (observable, oldValue, newValue) -> { - - var jmeApplication = JmeApplication.getInstance(); - var stage = EditorUtil.getFxStage(); - - if (newValue || stage.isFocused()) { - jmeApplication.setPaused(false); - return; - } - - var editorConfig = EditorConfig.getInstance(); - if (!editorConfig.getBoolean(PREF_STOP_RENDER_ON_LOST_FOCUS, PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS)) { - jmeApplication.setPaused(false); - return; - } - - var application = JfxApplication.getInstance(); - var window = ArrayUtils.getInReadLock(application.openedWindows, - windows -> windows.search(Window::isFocused)); - - jmeApplication.setPaused(window == null); - }; - } - - /** - * Start. - */ - @FromAnyThread - public static void start() { - launch(); - } - - @FromAnyThread - private static void printError(@NotNull Throwable throwable) { - throwable.printStackTrace(); - - var userHome = System.getProperty("user.home"); - var fileName = "jmonkeybuilder-error.log"; - - try (var out = new PrintStream(newOutputStream(Paths.get(userHome, fileName)))) { - throwable.printStackTrace(out); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * The list of opened windows. - */ - @NotNull - private final ConcurrentArray openedWindows; - - /** - * The JavaFX scene. - */ - @Nullable - private volatile EditorFxScene scene; - - /** - * The scene processor. - */ - @Nullable - private volatile FrameTransferSceneProcessor sceneProcessor; - - /** - * The stage. - */ - @Nullable - private Stage stage; - - public JfxApplication() { - EditorUtil.setJfxApplication(this); - this.openedWindows = ArrayFactory.newConcurrentStampedLockArray(Window.class); - } - - /** - * Request focus of this window. - */ - public void requestFocus() { - notNull(stage).requestFocus(); - } - - /** - * Add the new opened window. - * - * @param window the new opened window. - */ - @FxThread - public void addWindow(@NotNull Window window) { - window.focusedProperty().addListener(makeFocusedListener()); - ArrayUtils.runInWriteLock(openedWindows, window, Collection::add); - } - - /** - * Remove the opened window. - * - * @param window the opened window. - */ - @FxThread - public void removeWindow(@NotNull Window window) { - ArrayUtils.runInWriteLock(openedWindows, window, Array::slowRemove); - } - - /** - * Gets the last opened window. - * - * @return the last opened window. - */ - @FxThread - public @NotNull Window getLastWindow() { - return notNull(ArrayUtils.getInReadLock(openedWindows, Array::last)); - } - - @Override - @FxThread - public void start(@NotNull Stage stage) throws Exception { - JfxApplication.instance = this; - this.stage = stage; - - addWindow(stage); - try { - - // initialize javaFX events in javaFX thread. - ArrayFactory.asArray(ComboBoxBase.ON_SHOWN); - - var resourceManager = ResourceManager.getInstance(); - resourceManager.reload(); - - var initializationManager = InitializationManager.getInstance(); - initializationManager.onBeforeCreateJavaFxContext(); - - var pluginManager = PluginManager.getInstance(); - pluginManager.handlePlugins(editorPlugin -> editorPlugin.register(CssRegistry.getInstance())); - - LogView.getInstance(); - SvgImageLoaderFactory.install(); - ImageIO.read(getClass().getResourceAsStream("/ui/icons/test/test.jpg")); - - var icons = stage.getIcons(); - icons.add(new Image("/ui/icons/app/256x256.png")); - icons.add(new Image("/ui/icons/app/128x128.png")); - icons.add(new Image("/ui/icons/app/96x96.png")); - icons.add(new Image("/ui/icons/app/64x64.png")); - icons.add(new Image("/ui/icons/app/48x48.png")); - icons.add(new Image("/ui/icons/app/32x32.png")); - icons.add(new Image("/ui/icons/app/24x24.png")); - icons.add(new Image("/ui/icons/app/16x16.png")); - - var config = EditorConfig.getInstance(); - - stage.initStyle(StageStyle.DECORATED); - stage.setMinHeight(600); - stage.setMinWidth(800); - stage.setWidth(config.getScreenWidth()); - stage.setHeight(config.getScreenHeight()); - stage.setMaximized(config.isMaximized()); - stage.setTitle(Config.TITLE); - stage.show(); - - - if (!stage.isMaximized()) { - stage.centerOnScreen(); - } - - stage.widthProperty().addListener((observable, oldValue, newValue) -> { - if (stage.isMaximized()) return; - config.setScreenWidth(newValue.intValue()); - }); - stage.heightProperty().addListener((observable, oldValue, newValue) -> { - if (stage.isMaximized()) return; - config.setScreenHeight(newValue.intValue()); - }); - - stage.maximizedProperty() - .addListener((observable, oldValue, newValue) -> config.setMaximized(newValue)); - - buildScene(); - - } catch (Throwable e) { - LOGGER.error(this, e); - throw e; - } - } - - @Override - @FxThread - public void stop() throws Exception { - super.stop(); - onExit(); - } - - /** - * On exit. - */ - @FxThread - protected void onExit() { - - GAnalytics.forceSendEvent(GAEvent.Category.APPLICATION, - GAEvent.Action.APPLICATION_CLOSED, GAEvent.Label.THE_EDITOR_APP_WAS_CLOSED); - - var config = EditorConfig.getInstance(); - config.save(); - - var waiter = new CountDownLatch(1); - - var executor = JmeThreadExecutor.getInstance(); - executor.addToExecute(() -> { - JmeApplication.getInstance().destroy(); - waiter.countDown(); - }); - - GAnalytics.waitForSend(); - Utils.run(waiter::await); - } - - /** - * Build the scene. - */ - @FxThread - private void buildScene() { - this.scene = EditorFxSceneBuilder.build(notNull(stage)); - - var initializationManager = InitializationManager.getInstance(); - initializationManager.onAfterCreateJavaFxContext(); - - var pluginManager = PluginManager.getInstance(); - pluginManager.handlePlugins(editorPlugin -> { - editorPlugin.register(FileCreatorRegistry.getInstance()); - editorPlugin.register(EditorRegistry.getInstance()); - editorPlugin.register(FileIconManager.getInstance()); - editorPlugin.register(FileConverterRegistry.getInstance()); - editorPlugin.register(AssetTreeContextMenuFillerRegistry.getInstance()); - editorPlugin.register(TreeNodeFactoryRegistry.getInstance()); - editorPlugin.register(PropertyBuilderRegistry.getInstance()); - editorPlugin.register(FilePreviewFactoryRegistry.getInstance()); - editorPlugin.register(SettingsProviderRegistry.getInstance()); - }); - - var scene = getScene(); - - var jmeApplication = JmeApplication.getInstance(); - var executor = JmeThreadExecutor.getInstance(); - executor.addToExecute(() -> createSceneProcessor(scene, jmeApplication)); - - JmeFilePreviewManager.getInstance(); - - GAnalytics.forceSendEvent(GAEvent.Category.APPLICATION, - GAEvent.Action.APPLICATION_LAUNCHED, GAEvent.Label.THE_EDITOR_APP_WAS_LAUNCHED); - - var executorManager = ExecutorManager.getInstance(); - executorManager.addBackgroundTask(new CheckNewVersionTask()); - - var editorConfig = EditorConfig.getInstance(); - if (editorConfig.isAnalyticsQuestion()) { - return; - } - - editorConfig.set(PREF_ANALYTICS_GOOGLE, false); - editorConfig.save(); - - Platform.runLater(() -> { - - var stage = notNull(getStage()); - var confirmDialog = new ConfirmDialog(result -> { - - editorConfig.setAnalyticsQuestion(true); - editorConfig.set(PREF_ANALYTICS_GOOGLE, Boolean.TRUE.equals(result)); - editorConfig.save(); - - }, Messages.ANALYTICS_CONFIRM_DIALOG_MESSAGE); - - confirmDialog.show(stage); - }); - } - - @FxThread - private void createSceneProcessor(@NotNull EditorFxScene scene, @NotNull JmeApplication jmeApplication) { - - var sceneProcessor = bind(jmeApplication, scene.getCanvas(), jmeApplication.getViewPort()); - sceneProcessor.setEnabled(false); - sceneProcessor.setTransferMode(ON_CHANGES); - - this.sceneProcessor = sceneProcessor; - - var stage = notNull(getStage()); - stage.focusedProperty().addListener(makeFocusedListener()); - - Platform.runLater(scene::notifyFinishBuild); - } - - /** - * Get the current JavaFX scene. - * - * @return the JavaFX scene. - */ - @FromAnyThread - public @NotNull EditorFxScene getScene() { - return notNull(scene, "Scene can't be null."); - } - - /** - * Get the current stage of JavaFX. - * - * @return the current stage. - */ - @FromAnyThread - public @NotNull Stage getStage() { - return notNull(stage); - } - - /** - * Get the current scene processor of this application. - * - * @return the scene processor. - */ - @FromAnyThread - public @NotNull FrameTransferSceneProcessor getSceneProcessor() { - return notNull(sceneProcessor, "Scene processor can't be null."); - } -} diff --git a/src/main/java/com/ss/editor/config/Config.java b/src/main/java/com/ss/editor/config/Config.java deleted file mode 100644 index f642a0f1..00000000 --- a/src/main/java/com/ss/editor/config/Config.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.ss.editor.config; - -import com.ss.editor.JmeApplication; -import com.ss.editor.document.DocumentConfig; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.plugin.Version; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.os.OperatingSystem; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The configuration of this application. - * - * @author JavaSaBr - */ -public final class Config { - - /** - * The path to config file in classpath. - */ - @NotNull - private static final String CONFIG_RESOURCE_PATH = "/app-config.xml"; - - /** - * The name of editor's folder in user home folder. - */ - @NotNull - private static final String EDITOR_FOLDER_IN_USER_HOME = ".jmonkeybuilder"; - - /** - * The editor's title. - */ - @NotNull - public static final String TITLE = "jMonkeyBuilder"; - - /** - * The editor's version. - */ - @NotNull - public static final Version APP_VERSION = new Version("1.8.0"); - - /** - * The string version. - */ - @NotNull - public static final String STRING_VERSION = APP_VERSION.toString(); - - /** - * The server API version. - */ - @NotNull - public static final int SERVER_API_VERSION = 1; - - /** - * The path to application folder. - */ - @NotNull - public static final String PROJECT_PATH; - - /** - * The graphics adapter. - */ - @NotNull - public static final GraphicsDevice GRAPHICS_DEVICE; - - /** - * The operation system. - */ - @NotNull - public static final OperatingSystem OPERATING_SYSTEM; - - /** - * The remote control port. - */ - public static int REMOTE_CONTROL_PORT = -1; - - /** - * The flag to enable debug mode. - */ - public static boolean DEV_DEBUG; - - /** - * The flag to enable camera debug mode. - */ - public static boolean DEV_CAMERA_DEBUG; - - /** - * The flag to enable transformations debug mode. - */ - public static boolean DEV_TRANSFORMS_DEBUG; - - /** - * The flag to enable JavaFX debug mode. - */ - public static boolean DEV_DEBUG_JFX; - - /** - * The flag to enable JavaFX mouse input debug mode. - */ - public static boolean DEV_DEBUG_JFX_MOUSE_INPUT; - - /** - * The flag to enable javaFX key input debug mode. - */ - public static boolean DEV_DEBUG_JFX_KEY_INPUT; - - /** - * The flag to enable PBR render. - */ - public static boolean ENABLE_PBR; - - /** - * The flag to enable 3D part of this editor. - */ - public static boolean ENABLE_3D; - - static { - - var graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); - var device = graphicsEnvironment.getDefaultScreenDevice(); - - var vars = new DocumentConfig(EditorUtil.requireInputStream(CONFIG_RESOURCE_PATH)) - .parse(); - - DEV_DEBUG = vars.getBoolean("Dev.debug", false); - DEV_CAMERA_DEBUG = vars.getBoolean("Dev.cameraDebug", false); - DEV_TRANSFORMS_DEBUG = vars.getBoolean("Dev.transformsDebug", false); - DEV_DEBUG_JFX_MOUSE_INPUT = vars.getBoolean("Dev.jfxMouseInput", false); - DEV_DEBUG_JFX_KEY_INPUT = vars.getBoolean("Dev.jfxKeyInput", false); - DEV_DEBUG_JFX = vars.getBoolean("Dev.debugJFX", false); - ENABLE_PBR = vars.getBoolean("Graphics.enablePBR", true); - ENABLE_3D = vars.getBoolean("Graphics.enable3D", true); - - GRAPHICS_DEVICE = device; - OPERATING_SYSTEM = new OperatingSystem(); - - PROJECT_PATH = Utils.getRootFolderFromClass(JmeApplication.class).toString(); - } - - /** - * Get a folder to store log files. - * - * @return the path to a folder to store log files. - */ - public static @NotNull Path getFolderForLog() { - return getAppFolderInUserHome().resolve("log"); - } - - /** - * Get a path to the folder to store data in a user home. - * - * @return the path to the folder to store data in a user home. - */ - public static @NotNull Path getAppFolderInUserHome() { - var userHome = System.getProperty("user.home"); - return Paths.get(userHome, EDITOR_FOLDER_IN_USER_HOME); - } -} diff --git a/src/main/java/com/ss/editor/config/DefaultSettingsProvider.java b/src/main/java/com/ss/editor/config/DefaultSettingsProvider.java deleted file mode 100644 index 4448686b..00000000 --- a/src/main/java/com/ss/editor/config/DefaultSettingsProvider.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.ss.editor.config; - -import static com.ss.editor.config.DefaultSettingsProvider.Categories.EDITOR; -import static com.ss.editor.config.DefaultSettingsProvider.Categories.GRAPHICS; -import static com.ss.editor.config.DefaultSettingsProvider.Categories.OTHER; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.*; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; -import static com.ss.editor.extension.property.EditablePropertyType.*; -import static com.ss.rlib.common.util.array.ArrayFactory.asArray; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.settings.SettingsCategory; -import com.ss.editor.plugin.api.settings.SettingsPropertyDefinition; -import com.ss.editor.plugin.api.settings.SettingsProvider; -import com.ss.editor.ui.css.CssColorTheme; -import com.ss.editor.util.OpenGLVersion; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Set; - -/** - * The default implementation of {@link SettingsProvider} - * - * @author JavaSaBr - */ -public class DefaultSettingsProvider implements SettingsProvider { - - public interface Categories { - @NotNull SettingsCategory GRAPHICS = new SettingsCategory("core.graphics", Messages.SETTINGS_CATEGORY_GRAPHICS, 0); - @NotNull SettingsCategory EDITOR = new SettingsCategory("core.editor", Messages.SETTINGS_CATEGORY_EDITOR, 1); - @NotNull SettingsCategory OTHER = new SettingsCategory("core.other", Messages.SETTINGS_CATEGORY_OTHER, 2); - } - - public interface Preferences { - - @NotNull String PREF_OPEN_GL = "core.graphics.openGL.version"; - @NotNull String PREF_ANISOTROPY = "core.graphics.anisotropy"; - @NotNull String PREF_GAMMA_CORRECTION = "core.graphics.gammaCorrection"; - @NotNull String PREF_FRAME_RATE = "core.graphics.frame.rate"; - @NotNull String PREF_CAMERA_ANGLE = "core.graphics.camera.angle"; - @NotNull String PREF_FILTER_FXAA = "core.graphics.filter.fxaa"; - @NotNull String PREF_FILTER_TONEMAP = "core.graphics.filter.toneMap"; - @NotNull String PREF_FILTER_TONEMAP_WHITE_POINT = "core.graphics.filter.toneMap.whitePoint"; - @NotNull String PREF_STOP_RENDER_ON_LOST_FOCUS = "core.graphics.render.stopOnLostFocus"; - - @NotNull String PREF_USER_LIBRARY_FOLDER = "core.classpath.library.folder"; - @NotNull String PREF_USER_CLASSES_FOLDER = "core.classpath.classes.folder"; - - @NotNull String PREF_UI_THEME = "core.ui.theme"; - @NotNull String PREF_ANALYTICS_GOOGLE = "core.other.analytics.google"; - @NotNull String PREF_NATIVE_FILE_CHOOSER = "core.other.native.file.chooser"; - - @NotNull String PREF_FAST_SKY_FOLDER = "core.editor.fast.sky.folder"; - @NotNull String PREF_TANGENT_GENERATION = "core.editor.tangent.generation"; - @NotNull String PREF_FLIPPED_TEXTURES = "core.editor.texture.flipped"; - @NotNull String PREF_CAMERA_LAMP = "core.editor.camera.lamp"; - } - - public interface Defaults { - - @NotNull OpenGLVersion PREF_DEFAULT_OPEN_GL = OpenGLVersion.GL_33; - @NotNull CssColorTheme PREF_DEFAULT_THEME = CssColorTheme.DARK; - - @NotNull Vector3f PREF_DEFAULT_TONEMAP_WHITE_POINT = new Vector3f(11, 11, 11); - - int PREF_DEFAULT_ANISOTROPY = 16; - int PREF_DEFAULT_FRAME_RATE = 60; - int PREF_DEFAULT_CAMERA_ANGLE = 75; - - boolean PREF_DEFAULT_TONEMAP_FILTER = true; - boolean PREF_DEFAULT_GAMMA_CORRECTION = true; - boolean PREF_DEFAULT_NATIVE_FILE_CHOOSER = false; - boolean PREF_DEFAULT_FXAA_FILTER = true; - boolean PREF_DEFAULT_CAMERA_LIGHT = true; - boolean PREF_DEFAULT_TANGENT_GENERATION = true; - boolean PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS = true; - boolean PREF_DEFAULT_FLIPPED_TEXTURES = true; - boolean PREF_DEFAULT_ANALYTICS_GOOGLE = false; - } - - @NotNull - private static final Array ANISOTROPYCS = ArrayFactory.newArray(Integer.class); - - @NotNull - private static final Set REQUIRED_RESTART_PREFS = new HashSet<>(); - - @NotNull - private static final Set REQUIRED_UPDATE_CLASSPATH_PREFS = new HashSet<>(); - - @NotNull - private static final Set REQUIRED_RESHAPE_PREFS = new HashSet<>(); - - static { - ANISOTROPYCS.add(0); - ANISOTROPYCS.add(2); - ANISOTROPYCS.add(4); - ANISOTROPYCS.add(8); - ANISOTROPYCS.add(16); - REQUIRED_RESTART_PREFS.add(PREF_ANISOTROPY); - REQUIRED_RESTART_PREFS.add(PREF_GAMMA_CORRECTION); - REQUIRED_RESTART_PREFS.add(PREF_UI_THEME); - REQUIRED_RESTART_PREFS.add(PREF_OPEN_GL); - REQUIRED_RESTART_PREFS.add(PREF_FRAME_RATE); - REQUIRED_UPDATE_CLASSPATH_PREFS.add(PREF_USER_LIBRARY_FOLDER); - REQUIRED_UPDATE_CLASSPATH_PREFS.add(PREF_USER_CLASSES_FOLDER); - REQUIRED_RESHAPE_PREFS.add(PREF_CAMERA_ANGLE); - } - - @Override - @FxThread - public @NotNull Array getDefinitions() { - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final OpenGLVersion glVersion = editorConfig.getEnum(PREF_OPEN_GL, PREF_DEFAULT_OPEN_GL); - final int anisotropy = editorConfig.getInteger(PREF_ANISOTROPY, PREF_DEFAULT_ANISOTROPY); - final boolean gammaCorrection = editorConfig.getBoolean(PREF_GAMMA_CORRECTION, PREF_DEFAULT_GAMMA_CORRECTION); - final int frameRate = editorConfig.getInteger(PREF_FRAME_RATE, PREF_DEFAULT_FRAME_RATE); - final int cameraAngle = editorConfig.getInteger(PREF_CAMERA_ANGLE, PREF_DEFAULT_CAMERA_ANGLE); - final boolean fxaa = editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER); - final boolean stopRenderOnLostFocus = editorConfig.getBoolean(PREF_STOP_RENDER_ON_LOST_FOCUS, PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS); - final boolean tonemapFilter = editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER); - final Vector3f toneMapWhitePoint = editorConfig.getVector3f(PREF_FILTER_TONEMAP_WHITE_POINT, PREF_DEFAULT_TONEMAP_WHITE_POINT); - - final Array result = ArrayFactory.newArray(SettingsPropertyDefinition.class); - result.add(new SettingsPropertyDefinition(ENUM, Messages.SETTINGS_PROPERTY_OPEN_GL, PREF_OPEN_GL, GRAPHICS, glVersion)); - result.add(new SettingsPropertyDefinition(OBJECT_FROM_LIST, Messages.SETTINGS_PROPERTY_ANISOTROPY, PREF_ANISOTROPY, GRAPHICS, anisotropy, ANISOTROPYCS)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_GAMMA_CORRECTION, PREF_GAMMA_CORRECTION, GRAPHICS, gammaCorrection)); - result.add(new SettingsPropertyDefinition(INTEGER, Messages.SETTINGS_PROPERTY_FRAME_RATE, PREF_FRAME_RATE, GRAPHICS, frameRate, 10, 120)); - result.add(new SettingsPropertyDefinition(INTEGER, Messages.SETTINGS_PROPERTY_CAMERA_ANGLE, PREF_CAMERA_ANGLE, GRAPHICS, cameraAngle, 45, 110)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_FXAA, PREF_FILTER_FXAA, GRAPHICS, fxaa)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_STOP_RENDER_ON_LOST_FOCUS, PREF_STOP_RENDER_ON_LOST_FOCUS, GRAPHICS, stopRenderOnLostFocus)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_TONEMAP_FILTER, PREF_FILTER_TONEMAP, GRAPHICS, tonemapFilter)); - result.add(new SettingsPropertyDefinition(VECTOR_3F, asArray(PREF_FILTER_TONEMAP), Messages.SETTINGS_PROPERTY_TONEMAP_FILTER_WHITE_POINT, PREF_FILTER_TONEMAP_WHITE_POINT, GRAPHICS, toneMapWhitePoint)); - - final boolean tangentGeneration = editorConfig.getBoolean(PREF_TANGENT_GENERATION, PREF_DEFAULT_TANGENT_GENERATION); - final boolean flippedTextures = editorConfig.getBoolean(PREF_FLIPPED_TEXTURES, PREF_DEFAULT_FLIPPED_TEXTURES); - final boolean cameraLight = editorConfig.getBoolean(PREF_CAMERA_LAMP, PREF_DEFAULT_CAMERA_LIGHT); - final Path fastSkyFolder = editorConfig.getFile(PREF_FAST_SKY_FOLDER); - - result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_FAST_SKY_FOLDER, PREF_FAST_SKY_FOLDER, EDITOR, fastSkyFolder)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_TANGENT_GENERATION, PREF_TANGENT_GENERATION, EDITOR, tangentGeneration)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_FLIPPED_TEXTURE, PREF_FLIPPED_TEXTURES, EDITOR, flippedTextures)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_EDITOR_CAMERA_LAMP, PREF_CAMERA_LAMP, EDITOR, cameraLight)); - - final CssColorTheme theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); - final Path libraryFolder = editorConfig.getFile(PREF_USER_LIBRARY_FOLDER); - final Path classesFolder = editorConfig.getFile(PREF_USER_CLASSES_FOLDER); - final boolean googleAnalytics = editorConfig.getBoolean(PREF_ANALYTICS_GOOGLE, PREF_DEFAULT_ANALYTICS_GOOGLE); - final boolean nativeFileChooser = editorConfig.getBoolean(PREF_NATIVE_FILE_CHOOSER, PREF_DEFAULT_NATIVE_FILE_CHOOSER); - - result.add(new SettingsPropertyDefinition(ENUM, Messages.SETTINGS_PROPERTY_THEME, PREF_UI_THEME, OTHER, theme)); - result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_USER_LIBRARIES_FOLDER, PREF_USER_LIBRARY_FOLDER, OTHER, libraryFolder)); - result.add(new SettingsPropertyDefinition(EXTERNAL_FILE, Messages.SETTINGS_PROPERTY_USER_CLASSES_FOLDER, PREF_USER_CLASSES_FOLDER, OTHER, classesFolder)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_GOOGLE_ANALYTICS, PREF_ANALYTICS_GOOGLE, OTHER, googleAnalytics)); - result.add(new SettingsPropertyDefinition(BOOLEAN, Messages.SETTINGS_PROPERTY_NATIVE_FILE_CHOOSER, PREF_NATIVE_FILE_CHOOSER, OTHER, nativeFileChooser)); - - return result; - } - - @Override - @FxThread - public boolean isRequiredRestart(@NotNull final String propertyId) { - return REQUIRED_RESTART_PREFS.contains(propertyId); - } - - @Override - @FxThread - public boolean isRequiredReshape3DView(@NotNull final String propertyId) { - return REQUIRED_RESHAPE_PREFS.contains(propertyId); - } - - @Override - @FxThread - public boolean isRequiredUpdateClasspath(@NotNull final String propertyId) { - return REQUIRED_UPDATE_CLASSPATH_PREFS.contains(propertyId); - } -} diff --git a/src/main/java/com/ss/editor/control/brush/editor/scene/SceneEditorBrushControl.java b/src/main/java/com/ss/editor/control/brush/editor/scene/SceneEditorBrushControl.java deleted file mode 100644 index ab2a325b..00000000 --- a/src/main/java/com/ss/editor/control/brush/editor/scene/SceneEditorBrushControl.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ss.editor.control.brush.editor.scene; - -import com.ss.editor.control.brush.BrushControl; - -/** - * The interface to implement a brush in a scene editor. - * - * @author JavaSaBr - */ -public interface SceneEditorBrushControl extends BrushControl { -} diff --git a/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java deleted file mode 100644 index ff6cbab0..00000000 --- a/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ss.editor.control.painting.terrain; - -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.impl.AbstractPaintingControl; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of terrain tool. - * - * @author JavaSaBr - */ -public class TerrainToolControl extends AbstractPaintingControl { - - public TerrainToolControl(@NotNull final TerrainPaintingComponent component) { - super(component); - } - - /** - * Get the change consumer. - * - * @return the change consumer. - */ - @FromAnyThread - protected @NotNull ModelChangeConsumer getChangeConsumer() { - return component.getChangeConsumer(); - } - - @Override - @JmeThread - public @Nullable Spatial getPaintedModel() { - return component.getPaintedObject(); - } -} diff --git a/src/main/java/com/ss/editor/executor/EditorTaskExecutor.java b/src/main/java/com/ss/editor/executor/EditorTaskExecutor.java deleted file mode 100644 index ee3b832d..00000000 --- a/src/main/java/com/ss/editor/executor/EditorTaskExecutor.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ss.editor.executor; - -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The interface to implement a task executor. - * - * @author JavaSaBr - */ -public interface EditorTaskExecutor { - - /** - * Add the new task. - * - * @param task the new task. - */ - @FromAnyThread - void execute(@NotNull Runnable task); -} diff --git a/src/main/java/com/ss/editor/executor/impl/AbstractEditorTaskExecutor.java b/src/main/java/com/ss/editor/executor/impl/AbstractEditorTaskExecutor.java deleted file mode 100644 index 87dfe2eb..00000000 --- a/src/main/java/com/ss/editor/executor/impl/AbstractEditorTaskExecutor.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.ss.editor.executor.impl; - -import com.ss.editor.EditorThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.executor.EditorTaskExecutor; -import com.ss.rlib.common.concurrent.lock.LockFactory; -import com.ss.rlib.common.concurrent.lock.Lockable; -import com.ss.rlib.common.concurrent.util.ConcurrentUtils; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.Lock; - -/** - * The base implementation of the {@link JmeThreadExecutor}. - * - * @author JavaSaBr - */ -public abstract class AbstractEditorTaskExecutor extends EditorThread implements EditorTaskExecutor, Lockable { - - /** - * The logger. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(EditorTaskExecutor.class); - - /** - * The task list to execute for each iteration. - */ - @NotNull - protected final Array execute; - - /** - * The array of executed task of the iteration. - */ - @NotNull - final Array executed; - - /** - * The array of task to execute. - */ - @NotNull - final Array waitTasks; - - /** - * Is this executor waiting new tasks. - */ - @NotNull - final AtomicBoolean wait; - - /** - * The synchronizer. - */ - @NotNull - private final Lock lock; - - public AbstractEditorTaskExecutor() { - this.execute = createExecuteArray(); - this.executed = createExecuteArray(); - this.waitTasks = createExecuteArray(); - this.lock = LockFactory.newAtomicLock(); - this.wait = new AtomicBoolean(false); - } - - /** - * Create a new execute tasks array. - * - * @return the new execute tasks array. - */ - @FromAnyThread - private @NotNull Array createExecuteArray() { - return ArrayFactory.newArray(Runnable.class); - } - - @Override - @FromAnyThread - public void execute(@NotNull final Runnable task) { - lock(); - try { - waitTasks.add(task); - if (!wait.get()) { - return; - } - - synchronized (wait) { - if (wait.compareAndSet(true, false)) { - ConcurrentUtils.notifyAllInSynchronize(wait); - } - } - - } finally { - unlock(); - } - - if (!wait.get()) { - return; - } - - synchronized (wait) { - if (wait.compareAndSet(true, false)) { - ConcurrentUtils.notifyAllInSynchronize(wait); - } - } - } - - /** - * Execute the array of tasks. - * - * @param execute the execute - * @param executed the executed - */ - protected abstract void doExecute(@NotNull final Array execute, @NotNull final Array executed); - - @Override - public void run() { - while (true) { - - executed.clear(); - execute.clear(); - - lock(); - try { - - if (waitTasks.isEmpty()) { - wait.getAndSet(true); - } else { - execute.addAll(waitTasks); - } - - } finally { - unlock(); - } - - if (wait.get()) { - synchronized (wait) { - if (wait.get()) { - ConcurrentUtils.waitInSynchronize(wait); - } - } - } - - if (execute.isEmpty()) { - continue; - } - - doExecute(execute, executed); - - if (executed.isEmpty()) { - continue; - } - - lock(); - try { - waitTasks.removeAll(executed); - } finally { - unlock(); - } - } - } - - @Override - public void lock() { - lock.lock(); - } - - @Override - public void unlock() { - lock.unlock(); - } -} diff --git a/src/main/java/com/ss/editor/executor/impl/BackgroundEditorTaskExecutor.java b/src/main/java/com/ss/editor/executor/impl/BackgroundEditorTaskExecutor.java deleted file mode 100644 index 4f337ab2..00000000 --- a/src/main/java/com/ss/editor/executor/impl/BackgroundEditorTaskExecutor.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ss.editor.executor.impl; - -import static java.lang.Math.min; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link JmeThreadExecutor} for executing task in the background. - * - * @author JavaSaBr - */ -public class BackgroundEditorTaskExecutor extends AbstractEditorTaskExecutor { - - /** - * The runtime of this process. - */ - private static final Runtime RUNTIME = Runtime.getRuntime(); - - /** - * The max count of task to execute using the same time. - */ - private static final int PROP_MAXIMUM_UPDATE = 500 / RUNTIME.availableProcessors(); - - /** - * The max count of task to execute in the one iteration. - */ - private static final int PROP_EXECUTE_LIMIT = 5; - - public BackgroundEditorTaskExecutor(final int order) { - setName(BackgroundEditorTaskExecutor.class.getSimpleName() + "_" + order); - setPriority(NORM_PRIORITY - 2); - start(); - } - - @Override - protected void doExecute(@NotNull final Array execute, @NotNull final Array executed) { - - final Runnable[] array = execute.array(); - - for (int i = 0, length = min(execute.size(), PROP_MAXIMUM_UPDATE); i < length; ) { - for (int count = 0; count < PROP_EXECUTE_LIMIT && i < length; count++, i++) { - - final Runnable task = array[i]; - task.run(); - - executed.add(task); - } - } - } -} diff --git a/src/main/java/com/ss/editor/executor/impl/JmeThreadExecutor.java b/src/main/java/com/ss/editor/executor/impl/JmeThreadExecutor.java deleted file mode 100644 index db3d2276..00000000 --- a/src/main/java/com/ss/editor/executor/impl/JmeThreadExecutor.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.ss.editor.executor.impl; - -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.util.EditorUtil; - -import org.jetbrains.annotations.NotNull; - -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.array.ConcurrentArray; - -/** - * The executor to execute tasks in the editor thread. - * - * @author JavaSaBr - */ -public class JmeThreadExecutor { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(JmeThreadExecutor.class); - - @NotNull - private static final JmeThreadExecutor INSTANCE = new JmeThreadExecutor(); - - @FromAnyThread - public static @NotNull JmeThreadExecutor getInstance() { - return INSTANCE; - } - - /** - * The list of waited tasks. - */ - @NotNull - private final ConcurrentArray waitTasks; - - /** - * The list with tasks to execute. - */ - @NotNull - private final Array execute; - - private JmeThreadExecutor() { - this.waitTasks = ArrayFactory.newConcurrentAtomicARSWLockArray(Runnable.class); - this.execute = ArrayFactory.newArray(Runnable.class); - } - - /** - * Add a task to execute. - * - * @param task the task. - */ - @FromAnyThread - public void addToExecute(@NotNull final Runnable task) { - ArrayUtils.runInWriteLock(waitTasks, task, (tasks, toAdd) -> tasks.add(task)); - } - - /** - * Execute waited tasks. - */ - @JmeThread - public void execute() { - - if (waitTasks.isEmpty()) { - return; - } - - ArrayUtils.runInWriteLock(waitTasks, execute, ArrayUtils::move); - try { - execute.forEach(JmeThreadExecutor::execute); - } finally { - execute.clear(); - } - } - - @JmeThread - private static void execute(@NotNull final Runnable runnable) { - try { - runnable.run(); - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, getInstance(), e); - } - } -} diff --git a/src/main/java/com/ss/editor/file/converter/FileConverterRegistry.java b/src/main/java/com/ss/editor/file/converter/FileConverterRegistry.java deleted file mode 100644 index 3ba05f18..00000000 --- a/src/main/java/com/ss/editor/file/converter/FileConverterRegistry.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.ss.editor.file.converter; - -import static com.ss.rlib.common.util.FileUtils.containsExtensions; -import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.file.converter.impl.*; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The registry of file converters. - * - * @author JavaSaBr - */ -public class FileConverterRegistry { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(FileConverterRegistry.class); - - @NotNull - private static final FileConverterRegistry INSTANCE = new FileConverterRegistry(); - - public static @NotNull FileConverterRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of converters. - */ - @NotNull - private final Array descriptions; - - private FileConverterRegistry() { - this.descriptions = ArrayFactory.newArray(FileConverterDescription.class); - register(BlendToJ3oFileConverter.DESCRIPTION); - register(FbxToJ3oFileConverter.DESCRIPTION); - register(ObjToJ3oFileConverter.DESCRIPTION); - register(SceneToJ3oFileConverter.DESCRIPTION); - register(MeshXmlToJ3oFileConverter.DESCRIPTION); - register(XbufToJ3oFileConverter.DESCRIPTION); - register(GltfToJ3oFileConverter.DESCRIPTION); - } - - /** - * Add the new file converter descriptor. - * - * @param description the new descriptor. - */ - @FromAnyThread - public void register(@NotNull final FileConverterDescription description) { - this.descriptions.add(description); - } - - /** - * Get the list of converters. - * - * @return the list of converters. - */ - @FromAnyThread - private @NotNull Array getDescriptions() { - return descriptions; - } - - /** - * Get the list of available converters for the file. - * - * @param path the path. - * @return the list of available converters. - */ - @FromAnyThread - public @NotNull Array getDescriptions(@NotNull final Path path) { - return getDescriptions().stream() - .filter(desc -> containsExtensions(desc.getExtensions(), path)) - .collect(toArray(FileConverterDescription.class)); - } - - /** - * Create a file converter using the converter description. - * - * @param description the converter description. - * @param file the file. - * @return the new converter. - */ - @FromAnyThread - public FileConverter newCreator(@NotNull final FileConverterDescription description, @NotNull final Path file) { - return description.getConstructor().get(); - } -} diff --git a/src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandlerFactory.java b/src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandlerFactory.java deleted file mode 100644 index 5c940a4f..00000000 --- a/src/main/java/com/ss/editor/file/delete/handler/FileDeleteHandlerFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ss.editor.file.delete.handler; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.file.delete.handler.impl.DeleteMaterialsModelFileDeleteHandler; -import org.jetbrains.annotations.NotNull; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; - -import java.nio.file.Path; - -/** - * The factory of delete handlers of deleted file. - * - * @author JavaSaBr - */ -public class FileDeleteHandlerFactory { - - @NotNull - private static final Array HANDLERS = ArrayFactory.newArray(FileDeleteHandler.class); - - static { - HANDLERS.add(new DeleteMaterialsModelFileDeleteHandler()); - } - - /** - * Find handlers for the file. - * - * @param file the file. - * @return the list of handlers. - */ - @FromAnyThread - public static @NotNull Array findFor(@NotNull final Path file) { - - final Array result = ArrayFactory.newArray(FileDeleteHandler.class); - - HANDLERS.forEach(result, file, (handler, toCollect, f) -> handler.isNeedHandle(f), - (handler, toCollect, f) -> toCollect.add(handler.clone())); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java b/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java deleted file mode 100644 index d3f85d33..00000000 --- a/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.file.delete.handler.impl; - -import com.ss.editor.file.delete.handler.FileDeleteHandler; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The base implementation of {@link FileDeleteHandler}. - * - * @author JavaSaBr - */ -public abstract class AbstractFileDeleteHandler implements FileDeleteHandler { - - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(FileDeleteHandler.class); - - @Override - public void preDelete(@NotNull final Path file) { - } - - @Override - public void postDelete(@NotNull final Path file) { - - } - - @Override - public boolean isNeedHandle(@NotNull final Path file) { - return false; - } - - @Override - public @NotNull FileDeleteHandler clone() { - try { - return (FileDeleteHandler) super.clone(); - } catch (final CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/com/ss/editor/filter/EditorFxaaFilter.java b/src/main/java/com/ss/editor/filter/EditorFxaaFilter.java deleted file mode 100644 index 759a4d87..00000000 --- a/src/main/java/com/ss/editor/filter/EditorFxaaFilter.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.ss.editor.filter; - -import com.jme3.post.filters.FXAAFilter; -import com.jme3.texture.Texture; -import org.jetbrains.annotations.NotNull; - -/** - * The changed implementation of {@link FXAAFilter} for this editor. - * - * @author JavaSaBr - */ -public class EditorFxaaFilter extends FXAAFilter { - - @Override - protected boolean isRequiresDepthTexture() { - return true; - } - - @Override - protected void setDepthTexture(@NotNull final Texture depthTexture) { - } -} diff --git a/src/main/java/com/ss/editor/manager/ClasspathManager.java b/src/main/java/com/ss/editor/manager/ClasspathManager.java deleted file mode 100644 index 6cc1f336..00000000 --- a/src/main/java/com/ss/editor/manager/ClasspathManager.java +++ /dev/null @@ -1,535 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_USER_CLASSES_FOLDER; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_USER_LIBRARY_FOLDER; -import static com.ss.rlib.common.util.array.ArrayFactory.toArray; -import com.jme3.asset.AssetManager; -import com.ss.editor.FileExtensions; -import com.ss.editor.JmeApplication; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.classpath.ClassPathScanner; -import com.ss.rlib.common.classpath.ClassPathScannerFactory; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.plugin.PluginContainer; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.EnumSet; -import java.util.Set; - -/** - * The class to manage classpath. - * - * @author JavaSaBr - */ -public class ClasspathManager { - - public enum Scope { - CORE, - CUSTOM, - PLUGINS, - LOCAL_LIBRARIES, - LOCAL_CLASSES; - - @NotNull - public static final Set ONLY_CORE = EnumSet.of(CORE); - - @NotNull - public static final Set CORE_AND_CUSTOM_AND_LOCAL = EnumSet.of(CORE, CUSTOM, LOCAL_CLASSES, LOCAL_LIBRARIES); - - @NotNull - public static final Set ALL = EnumSet.allOf(Scope.class); - } - - @NotNull - private static final EditorConfig EDITOR_CONFIG = EditorConfig.getInstance(); - - @NotNull - private static final String[] JAR_EXTENSIONS = toArray(FileExtensions.JAVA_LIBRARY); - - @NotNull - public static final Array CORE_LIBRARIES_NAMES = ArrayFactory.asArray( - "jme3-core", "jme3-terrain", "jme3-effects", - "jme3-testdata", "jme3-plugins", "tonegod", "jmonkeybuilder" - ); - - @Nullable - private static ClasspathManager instance; - - @FromAnyThread - public static @NotNull ClasspathManager getInstance() { - if (instance == null) instance = new ClasspathManager(); - return instance; - } - - /** - * The core classpath scanner. - */ - @NotNull - private final ClassPathScanner coreScanner; - - /** - * The custom classpath scanner. - */ - @Nullable - private volatile ClassPathScanner customScanner; - - /** - * The local libraries scanner. - */ - @Nullable - private volatile ClassPathScanner localLibrariesScanner; - - /** - * The local classes scanner. - */ - @Nullable - private volatile ClassPathScanner localClassesScanner; - - /** - * The libraries class loader. - */ - @Nullable - private volatile URLClassLoader librariesLoader; - - /** - * The classes class loader. - */ - @Nullable - private volatile URLClassLoader classesLoader; - - /** - * The local libraries class loader. - */ - @Nullable - private volatile URLClassLoader localLibrariesLoader; - - /** - * The local classes class loader. - */ - @Nullable - private volatile URLClassLoader localClassesLoader; - - private ClasspathManager() { - InitializeManager.valid(getClass()); - - coreScanner = ClassPathScannerFactory.newManifestScanner(JmeApplication.class, "Class-Path"); - coreScanner.setUseSystemClasspath(true); - coreScanner.scan(path -> { - - if (Files.isDirectory(Paths.get(path))) { - return true; - } else if (CORE_LIBRARIES_NAMES.search(path, (pattern, pth) -> pth.contains(pattern)) == null) { - return false; - } else if (path.contains("natives")) { - return false; - } else if (path.contains("sources") || path.contains("javadoc")) { - return false; - } - - return true; - }); - - final ExecutorManager executorManager = ExecutorManager.getInstance(); - executorManager.addJmeTask(this::reload); - } - - /** - * Get all available resources from classpath. - * - * @return the list of resources. - */ - public @NotNull Array getAllResources() { - final Array result = ArrayFactory.newArray(String.class); - coreScanner.getAllResources(result); - return result; - } - - /** - * Reload custom classes and libraries. - */ - public synchronized void reload() { - updateLibraries(); - updateClasses(); - - final URLClassLoader librariesLoader = getLibrariesLoader(); - final URLClassLoader classesLoader = getClassesLoader(); - - if (librariesLoader == null && classesLoader == null) { - this.customScanner = null; - return; - } - - final ClassLoader classLoader = classesLoader == null ? librariesLoader : classesLoader; - final ClassPathScanner scanner = classesLoader == null ? ClassPathScannerFactory.newDefaultScanner() : - ClassPathScannerFactory.newDefaultScanner(classLoader); - - final Array urls = ArrayFactory.newArray(URL.class); - - if (librariesLoader != null) { - urls.addAll(librariesLoader.getURLs()); - } - - if (classesLoader != null) { - urls.addAll(classesLoader.getURLs()); - } - - final String[] paths = urls.stream().map(url -> Utils.get(url, URL::toURI)) - .map(Paths::get) - .map(Path::toString) - .toArray(String[]::new); - - scanner.addAdditionalPaths(paths); - scanner.setUseSystemClasspath(false); - scanner.scan(); - - this.customScanner = scanner; - } - - /** - * Update libraries loader. - */ - @FromAnyThread - private void updateLibraries() { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final URLClassLoader currentClassLoader = getLibrariesLoader(); - - if (currentClassLoader != null) { - assetManager.removeClassLoader(currentClassLoader); - setLibrariesLoader(null); - } - - final Path path = EDITOR_CONFIG.getFile(PREF_USER_LIBRARY_FOLDER); - if (path == null) { - return; - } - - final Array jars = FileUtils.getFiles(path, false, JAR_EXTENSIONS); - final URL[] urls = jars.stream() - .map(FileUtils::toUrl) - .toArray(URL[]::new); - - final URLClassLoader classLoader = new URLClassLoader(urls, getClass().getClassLoader()); - - assetManager.addClassLoader(classLoader); - setLibrariesLoader(classLoader); - } - - /** - * Update compiled classes loader. - */ - @FromAnyThread - private void updateClasses() { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final URLClassLoader currentClassLoader = getClassesLoader(); - - if (currentClassLoader != null) { - assetManager.removeClassLoader(currentClassLoader); - setClassesLoader(null); - } - - final Path path = EDITOR_CONFIG.getFile(PREF_USER_CLASSES_FOLDER); - if (path == null) { - return; - } - - final Array folders = ArrayFactory.newArray(Path.class); - - Utils.run(path, folders, (dir, toStore) -> { - final DirectoryStream stream = Files.newDirectoryStream(dir); - stream.forEach(subFile -> { - if (Files.isDirectory(subFile)) { - toStore.add(subFile); - } - }); - }); - - final URL[] urls = folders.stream() - .map(FileUtils::toUrl) - .toArray(URL[]::new); - - final ClassLoader librariesLoader = getLibrariesLoader(); - final ClassLoader parent = librariesLoader == null? getClass().getClassLoader() : librariesLoader; - final URLClassLoader classLoader = new URLClassLoader(urls, parent); - - assetManager.addClassLoader(classLoader); - setClassesLoader(classLoader); - } - - /** - * Load local libraries. - */ - @FromAnyThread - public synchronized @NotNull ClasspathManager loadLocalLibraries(@NotNull Array libraries) { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final URLClassLoader currentClassLoader = getLocalLibrariesLoader(); - - if (currentClassLoader != null) { - assetManager.removeClassLoader(currentClassLoader); - setLocalLibrariesLoader(null); - } - - if (libraries.isEmpty()) { - this.localLibrariesScanner = null; - return this; - } - - final URL[] urlArray = libraries.stream() - .map(FileUtils::toUrl) - .toArray(URL[]::new); - - final URLClassLoader classLoader = new URLClassLoader(urlArray, getClass().getClassLoader()); - - assetManager.addClassLoader(classLoader); - setLocalLibrariesLoader(classLoader); - - final ClassPathScanner scanner = ClassPathScannerFactory.newDefaultScanner(classLoader); - final Array urls = ArrayFactory.asArray(classLoader.getURLs()); - final String[] paths = urls.stream().map(url -> Utils.get(url, URL::toURI)) - .map(Paths::get) - .map(Path::toString) - .toArray(String[]::new); - - scanner.addAdditionalPaths(paths); - scanner.setUseSystemClasspath(false); - scanner.scan(); - - this.localLibrariesScanner = scanner; - return this; - } - - /** - * Load local classes. - */ - @FromAnyThread - public synchronized @NotNull ClasspathManager loadLocalClasses(@Nullable final Path output) { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final URLClassLoader currentClassLoader = getLocalClassesLoader(); - - if (currentClassLoader != null) { - assetManager.removeClassLoader(currentClassLoader); - setLocalClassesLoader(null); - } - - if (output == null || !Files.exists(output)) { - this.localClassesScanner = null; - return this; - } - - final Array folders = ArrayFactory.newArray(Path.class); - - Utils.run(output, folders, (dir, toStore) -> { - final DirectoryStream stream = Files.newDirectoryStream(dir); - stream.forEach(subFile -> { - if (Files.isDirectory(subFile)) { - toStore.add(subFile); - } - }); - }); - - final URL[] urlArray = folders.stream() - .map(FileUtils::toUrl) - .toArray(URL[]::new); - - final ClassLoader librariesLoader = getLocalLibrariesLoader(); - final ClassLoader parent = librariesLoader == null? getClass().getClassLoader() : librariesLoader; - final URLClassLoader classLoader = new URLClassLoader(urlArray, parent); - - assetManager.addClassLoader(classLoader); - setLocalClassesLoader(classLoader); - - final ClassPathScanner scanner = ClassPathScannerFactory.newDefaultScanner(classLoader); - final Array urls = ArrayFactory.asArray(classLoader.getURLs()); - final String[] paths = urls.stream().map(url -> Utils.get(url, URL::toURI)) - .map(Paths::get) - .map(Path::toString) - .toArray(String[]::new); - - scanner.addAdditionalPaths(paths); - scanner.setUseSystemClasspath(false); - scanner.scan(); - - this.localClassesScanner = scanner; - return this; - } - - /** - * @param librariesLoader the additional class loader. - */ - @FromAnyThread - private void setLibrariesLoader(@Nullable final URLClassLoader librariesLoader) { - this.librariesLoader = librariesLoader; - } - - /** - * Get the library loader. - * - * @return the library loader. - */ - @FromAnyThread - public @Nullable URLClassLoader getLibrariesLoader() { - return librariesLoader; - } - - /** - * Set the classes loader. - * - * @param classesLoader the classes loader. - */ - @FromAnyThread - private void setClassesLoader(@Nullable final URLClassLoader classesLoader) { - this.classesLoader = classesLoader; - } - - /** - * Get the classes loader. - * - * @return the classes loader. - */ - @FromAnyThread - public @Nullable URLClassLoader getClassesLoader() { - return classesLoader; - } - - /** - * Get the local libraries class loader. - * - * @return the local libraries class loader. - */ - @FromAnyThread - private @Nullable URLClassLoader getLocalLibrariesLoader() { - return localLibrariesLoader; - } - - /** - * Set the local libraries class loader. - * - * @param localLibrariesLoader the local libraries class loader. - */ - @FromAnyThread - private void setLocalLibrariesLoader(@Nullable final URLClassLoader localLibrariesLoader) { - this.localLibrariesLoader = localLibrariesLoader; - } - - /** - * Get the local classes class loader. - * - * @return the local classes class loader. - */ - @FromAnyThread - private @Nullable URLClassLoader getLocalClassesLoader() { - return localClassesLoader; - } - - /** - * Set the local classes class loader. - * - * @param localClassesLoader the local classes class loader. - */ - @FromAnyThread - private void setLocalClassesLoader(@Nullable final URLClassLoader localClassesLoader) { - this.localClassesLoader = localClassesLoader; - } - - /** - * Find all implementations of the interface class. - * - * @param the type of an interface. - * @param interfaceClass the interface class. - * @return the list of all available implementations. - */ - @FromAnyThread - public @NotNull Array> findImplements(@NotNull final Class interfaceClass) { - return findImplements(interfaceClass, Scope.ONLY_CORE); - } - - /** - * Get the custom scanner. - * - * @return the custom scanner. - */ - @FromAnyThread - private @Nullable ClassPathScanner getCustomScanner() { - return customScanner; - } - - /** - * Get the local libraries scanner. - * - * @return the local libraries scanner. - */ - @FromAnyThread - private @Nullable ClassPathScanner getLocalLibrariesScanner() { - return localLibrariesScanner; - } - - /** - * Get the local classes scanner. - * - * @return the local classes scanner. - */ - @FromAnyThread - private @Nullable ClassPathScanner getLocalClassesScanner() { - return localClassesScanner; - } - - /** - * Find all implementations of the interface class. - * - * @param the type of an interface. - * @param interfaceClass the interface class. - * @param scope the scope. - * @return the list of all available implementations. - */ - @FromAnyThread - public @NotNull Array> findImplements(@NotNull final Class interfaceClass, - @NotNull final Set scope) { - - final Array> result = ArrayFactory.newArray(Class.class); - - if (scope.contains(Scope.CORE)) { - coreScanner.findImplements(result, interfaceClass); - } - - final ClassPathScanner customScanner = getCustomScanner(); - if (customScanner != null && scope.contains(Scope.CUSTOM)) { - customScanner.findImplements(result, interfaceClass); - } - - final ClassPathScanner localLibrariesScanner = getLocalLibrariesScanner(); - if (localLibrariesScanner != null && scope.contains(Scope.LOCAL_LIBRARIES)) { - localLibrariesScanner.findImplements(result, interfaceClass); - } - - final ClassPathScanner localClassesScanner = getLocalClassesScanner(); - if (localClassesScanner != null && scope.contains(Scope.LOCAL_CLASSES)) { - localClassesScanner.findImplements(result, interfaceClass); - } - - if (scope.contains(Scope.PLUGINS)) { - final PluginManager pluginManager = PluginManager.getInstance(); - pluginManager.handlePlugins(plugin -> { - final PluginContainer container = plugin.getContainer(); - container.getScanner().findImplements(result, interfaceClass); - }); - } - - return result; - } -} diff --git a/src/main/java/com/ss/editor/manager/ExecutorManager.java b/src/main/java/com/ss/editor/manager/ExecutorManager.java deleted file mode 100644 index 6625be51..00000000 --- a/src/main/java/com/ss/editor/manager/ExecutorManager.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.ss.editor.manager; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.executor.EditorTaskExecutor; -import com.ss.editor.executor.impl.BackgroundEditorTaskExecutor; -import com.ss.editor.executor.impl.FxEditorTaskExecutor; -import com.ss.editor.executor.impl.JmeThreadExecutor; -import com.ss.rlib.common.concurrent.atomic.AtomicInteger; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * The class to manage executing some tasks in the some threads. - * - * @author JavaSaBr - */ -public class ExecutorManager { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(ExecutorManager.class); - - @NotNull - private static final Runtime RUNTIME = Runtime.getRuntime(); - - private static final int PROP_BACKGROUND_TASK_EXECUTORS = RUNTIME.availableProcessors(); - - @Nullable - private static ExecutorManager instance; - - public static @NotNull ExecutorManager getInstance() { - if (instance == null) instance = new ExecutorManager(); - return instance; - } - - /** - * The service to execute tasks using schedule. - */ - @NotNull - private final ScheduledExecutorService scheduledExecutorService; - - /** - * The list of background tasks executors. - */ - @NotNull - private final EditorTaskExecutor[] backgroundTaskExecutors; - - /** - * The executor of editor tasks. - */ - @NotNull - private final JmeThreadExecutor jmeTasksExecutor; - - /** - * The executor of javaFX tasks. - */ - @NotNull - private final EditorTaskExecutor fxEditorTaskExecutor; - - /** - * The index of a next background executor. - */ - @NotNull - private final AtomicInteger nextBackgroundTaskExecutor; - - private ExecutorManager() { - - this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); - this.backgroundTaskExecutors = new EditorTaskExecutor[PROP_BACKGROUND_TASK_EXECUTORS]; - - for (int i = 0, length = backgroundTaskExecutors.length; i < length; i++) { - backgroundTaskExecutors[i] = new BackgroundEditorTaskExecutor(i + 1); - } - - this.jmeTasksExecutor = JmeThreadExecutor.getInstance(); - this.fxEditorTaskExecutor = new FxEditorTaskExecutor(); - - this.nextBackgroundTaskExecutor = new AtomicInteger(0); - - LOGGER.debug("initialized."); - } - - /** - * Add a new background task. - * - * @param task the background task. - */ - @FromAnyThread - public void addBackgroundTask(@NotNull final Runnable task) { - - var executors = getBackgroundTaskExecutors(); - var nextTaskExecutor = getNextBackgroundTaskExecutor(); - - var index = nextTaskExecutor.incrementAndGet(); - - if (index < executors.length) { - executors[index].execute(task); - } else { - nextTaskExecutor.set(0); - executors[0].execute(task); - } - } - - /** - * Add the new task to be executed in the JavaFX thread. - * - * @param task the task. - */ - @FromAnyThread - public void addFxTask(@NotNull Runnable task) { - getFxTaskExecutor().execute(task); - } - - /** - * Add a new editor task. - * - * @param task the editor task. - */ - @FromAnyThread - public void addJmeTask(@NotNull Runnable task) { - getJmeTasksExecutor().addToExecute(task); - } - - /** - * Get the list of background tasks executors. - * - * @return the list of background tasks executors. - */ - @FromAnyThread - private @NotNull EditorTaskExecutor[] getBackgroundTaskExecutors() { - return backgroundTaskExecutors; - } - - /** - * Get the executor of javaFX tasks. - * - * @return the executor of javaFX tasks. - */ - @FromAnyThread - private @NotNull EditorTaskExecutor getFxTaskExecutor() { - return fxEditorTaskExecutor; - } - - /** - * Get the index of a next background executor. - * - * @return the index of a next background executor. - */ - @FromAnyThread - private @NotNull AtomicInteger getNextBackgroundTaskExecutor() { - return nextBackgroundTaskExecutor; - } - - /** - * Get the executor of jME tasks. - * - * @return the executor of jME tasks. - */ - @FromAnyThread - private @NotNull JmeThreadExecutor getJmeTasksExecutor() { - return jmeTasksExecutor; - } - - /** - * Add a scheduled task. - * - * @param runnable the scheduled task. - * @param timeout the timeout. - */ - @FromAnyThread - public void schedule(@NotNull Runnable runnable, long timeout) { - scheduledExecutorService.schedule(runnable, timeout, TimeUnit.MILLISECONDS); - } - - /** - * Add a scheduled task. - * - * @param runnable the scheduled task. - * @param delay the delay. - */ - @FromAnyThread - public void scheduleAtFixedRate(@NotNull Runnable runnable, long delay) { - scheduledExecutorService.scheduleAtFixedRate(runnable, delay, delay, TimeUnit.MILLISECONDS); - } -} diff --git a/src/main/java/com/ss/editor/manager/FileIconManager.java b/src/main/java/com/ss/editor/manager/FileIconManager.java deleted file mode 100644 index 12b8cc1d..00000000 --- a/src/main/java/com/ss/editor/manager/FileIconManager.java +++ /dev/null @@ -1,419 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.FileExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.css.CssColorTheme; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.svg.SvgImageLoader; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.IntegerDictionary; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.scene.image.Image; -import javafx.scene.paint.Color; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.function.BiFunction; - -/** - * The class to manage file icons. - * - * @author JavaSaBr - */ -public class FileIconManager { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(FileIconManager.class); - - /** - * The constant DEFAULT_FILE_ICON_SIZE. - */ - public static final int DEFAULT_FILE_ICON_SIZE = 16; - - @NotNull - private static final ObjectDictionary EXTENSION_TO_CONTENT_TYPE = DictionaryFactory.newObjectDictionary(); - - static { - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_JPEG, "image-jpeg"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_JPG, "image-jpeg"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_TIFF, "image-tiff"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_GIF, "image-gif"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_BMP, "image-bmp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_PNG, "image-png"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_TGA, "image-x-tga"); - EXTENSION_TO_CONTENT_TYPE.put("psd", "image-x-psd"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_DDS, "image"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.IMAGE_HDR, "image"); - - EXTENSION_TO_CONTENT_TYPE.put("ogg", "audio-x-generic"); - EXTENSION_TO_CONTENT_TYPE.put("wav", "audio-x-generic"); - EXTENSION_TO_CONTENT_TYPE.put("mp3", "audio-x-generic"); - - EXTENSION_TO_CONTENT_TYPE.put("txt", "text"); - EXTENSION_TO_CONTENT_TYPE.put("log", "text"); - - EXTENSION_TO_CONTENT_TYPE.put("zip", "application-zip"); - EXTENSION_TO_CONTENT_TYPE.put("rar", "application-rar"); - EXTENSION_TO_CONTENT_TYPE.put("gz", "application-x-gzip"); - EXTENSION_TO_CONTENT_TYPE.put("jar", "application-x-java-archive"); - - EXTENSION_TO_CONTENT_TYPE.put("java", "application-x-java"); - - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_OBJECT, "jme3"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_SHADER_NODE, "vector"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_SCENE, "j3s"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_MATERIAL, "parquet"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.JME_MATERIAL_DEFINITION, "text"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.MODEL_GLTF, "cube"); - - EXTENSION_TO_CONTENT_TYPE.put("obj", "x-office-drawing"); - EXTENSION_TO_CONTENT_TYPE.put("blend", "application-x-blender"); - EXTENSION_TO_CONTENT_TYPE.put("fbx", "fbx"); - EXTENSION_TO_CONTENT_TYPE.put("j3odata", "text"); - EXTENSION_TO_CONTENT_TYPE.put("xml", "text-xml"); - EXTENSION_TO_CONTENT_TYPE.put("exe", "exec"); - EXTENSION_TO_CONTENT_TYPE.put("sh", "text-x-script"); - EXTENSION_TO_CONTENT_TYPE.put("ico", "image-x-ico"); - EXTENSION_TO_CONTENT_TYPE.put("ani", "video-x-generic"); - - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_FRAGMENT, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_VERTEX, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_GEOM, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_LIB, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_TESSELLATION_CONTROL, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.GLSL_TESSELLATION_EVALUATION, "text-x-csharp"); - EXTENSION_TO_CONTENT_TYPE.put(FileExtensions.MODEL_XBUF, "image-svg+xml-compressed"); - } - - @NotNull - private static final Array MIME_TYPES_FOLDERS = ArrayFactory.newArray(Path.class); - - static { - MIME_TYPES_FOLDERS.add(Paths.get("/ui/icons/filetypes/emerald/mimetypes")); - MIME_TYPES_FOLDERS.add(Paths.get("/ui/icons/filetypes/")); - } - - @Nullable - private static FileIconManager instance; - - @FromAnyThread - public static @NotNull FileIconManager getInstance() { - if (instance == null) instance = new FileIconManager(); - return instance; - } - - /** - * The image cache. - */ - @NotNull - private final IntegerDictionary> imageCache; - - /** - * The cache of original images. - */ - @NotNull - private final ObjectDictionary originalImageCache; - - /** - * The cache of urs by a file extension. - */ - @NotNull - private final ObjectDictionary extensionToUrl; - - /** - * The list of icon finders. - */ - @NotNull - private final Array> iconFinders; - - private FileIconManager() { - InitializeManager.valid(getClass()); - this.iconFinders = ArrayFactory.newArray(BiFunction.class); - this.imageCache = DictionaryFactory.newIntegerDictionary(); - this.extensionToUrl = DictionaryFactory.newObjectDictionary(); - this.originalImageCache = DictionaryFactory.newObjectDictionary(); - } - - /** - * Register a new icon finder. It's a function which receives a file and - * its extension and should return an URL to load an image. - * - * @param iconFinder the icon finder. - */ - @FromAnyThread - public void register(@NotNull final BiFunction iconFinder) { - this.iconFinders.add(iconFinder); - } - - /** - * Get an icon of the file. - * - * @param path the file. - * @param size the icon size. - * @return the icon. - */ - @FxThread - public @NotNull Image getIcon(@NotNull final Path path, int size) { - return getIcon(path, Files.isDirectory(path), true, size); - } - - /** - * Get an icon of the file. - * - * @param path the file. - * @param directory the directory. - * @param tryToGetContentType true of we can try to get content type of the file. - * @param size the icon size. - * @return the icon. - */ - @FxThread - public @NotNull Image getIcon(@NotNull final Path path, final boolean directory, final boolean tryToGetContentType, - int size) { - - final String extension = directory ? "folder" : FileUtils.getExtension(path); - final Array> iconFinders = getIconFinders(); - - String url = extensionToUrl.get(extension); - if (url != null) { - return getImage(url, size); - } - - if (!iconFinders.isEmpty()) { - for (final BiFunction iconFinder : iconFinders) { - url = iconFinder.apply(path, extension); - - final ClassLoader classLoader = iconFinder.getClass().getClassLoader(); - if (url == null || !EditorUtil.checkExists(url, classLoader)) { - continue; - } - - extensionToUrl.put(extension, url); - - return getImage(url, classLoader, size); - } - } - - String contentType; - - if (directory) { - contentType = "folder"; - } else { - - contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); - - if (contentType == null && tryToGetContentType) { - try { - contentType = Files.probeContentType(path); - } catch (final IOException e) { - LOGGER.warning(e); - } - } - } - - if (contentType != null) { - contentType = contentType.replace("/", "-"); - } - - if (contentType == null) { - LOGGER.debug("not found content type for " + path); - contentType = "none"; - } - - for (final Path mimeTypes : MIME_TYPES_FOLDERS) { - - Path iconPath = mimeTypes.resolve(contentType + ".svg"); - url = toAssetPath(iconPath); - - if (!EditorUtil.checkExists(url)) { - contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); - iconPath = mimeTypes.resolve(contentType + ".svg"); - url = toAssetPath(iconPath); - } - - if (!EditorUtil.checkExists(url)) { - contentType = EXTENSION_TO_CONTENT_TYPE.get(extension); - iconPath = mimeTypes.resolve(contentType + ".png"); - url = toAssetPath(iconPath); - } - - if (EditorUtil.checkExists(url)) { - break; - } - } - - if (url == null || !EditorUtil.checkExists(url)) { - LOGGER.warning("not found image for contentType " + contentType + " and path " + path); - url = "/ui/icons/svg/document.svg"; - } - - extensionToUrl.put(extension, url); - - return getImage(url, size); - } - - - /** - * Get an image by the URL. - * - * @param url the url. - * @return the image. - */ - @FxThread - public @NotNull Image getImage(@NotNull final String url) { - return getImage(url, 16); - } - - /** - * Get an image by the URL. - * - * @param url the url. - * @param size the size. - * @return the image. - */ - @FxThread - public @NotNull Image getImage(@NotNull final String url, final int size) { - return getImage(url, size, true); - } - - /** - * Get an image by the URL. - * - * @param url the url. - * @param classLoader the class loader. - * @param size the size. - * @return the image. - */ - @FxThread - public @NotNull Image getImage(@NotNull final String url, @NotNull final ClassLoader classLoader, final int size) { - return getImage(url, classLoader, size, true); - } - - /** - * Get an image by the URL. - * - * @param url the url. - * @param size the size. - * @param useCache true if need to use cache. - * @return the image. - */ - @FxThread - public @NotNull Image getImage(@NotNull final String url, final int size, final boolean useCache) { - return getImage(url, getClass().getClassLoader(), size, useCache); - } - - /** - * Get an image by the URL. - * - * @param url the url. - * @param classLoader the class loader. - * @param size the size. - * @param useCache true if need to use cache. - * @return the image. - */ - @FxThread - public @NotNull Image getImage(@NotNull final String url, @NotNull final ClassLoader classLoader, final int size, - final boolean useCache) { - if (!useCache) { - return buildImage(url, classLoader, size); - } - - return imageCache.get(size, DictionaryFactory::newObjectDictionary) - .get(url, () -> buildImage(url, classLoader, size)); - } - - @FxThread - private @NotNull Image buildImage(@NotNull final String url, @NotNull final ClassLoader classLoader, - final int size) { - return buildImage(url, EditorUtil.getInputStream(url, classLoader), size); - } - - @FxThread - private @NotNull Image buildImage(@NotNull final String url, @Nullable final InputStream in, final int size) { - - final Image image; - - if (in != null) { - image = new Image(in, size, size, false, true); - } else { - image = new Image(url, size, size, false, true); - } - - if (!url.contains("icons/svg/")) { - originalImageCache.put(image, image); - return image; - } - - final EditorConfig config = EditorConfig.getInstance(); - final CssColorTheme theme = config.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); - - if (theme.needRepaintIcons()) { - try { - - final Color iconColor = theme.getIconColor(); - final Image coloredImage; - - SvgImageLoader.OVERRIDE_COLOR.set(iconColor); - try { - - if (in != null) { - coloredImage = new Image(in, size, size, false, true); - } else { - coloredImage = new Image(url, size, size, false, true); - } - - } finally { - SvgImageLoader.OVERRIDE_COLOR.set(null); - } - - originalImageCache.put(coloredImage, image); - - return coloredImage; - - } catch (final Throwable e) { - LOGGER.warning(e); - } - } - - originalImageCache.put(image, image); - - return image; - } - - /** - * Get an original image of the image. - * - * @param image the image. - * @return the original image. - */ - @FromAnyThread - public @NotNull Image getOriginal(@NotNull final Image image) { - return notNull(originalImageCache.get(image), "not found original for " + image.getUrl()); - } - - /** - * Get the list of icon finders. - * - * @return the list of icon finders. - */ - @FromAnyThread - private @NotNull Array> getIconFinders() { - return iconFinders; - } -} diff --git a/src/main/java/com/ss/editor/manager/InitializationManager.java b/src/main/java/com/ss/editor/manager/InitializationManager.java deleted file mode 100644 index 4366c570..00000000 --- a/src/main/java/com/ss/editor/manager/InitializationManager.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.ss.editor.manager; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -/** - * The class to manage initialization of some classes. - * - * @author JavaSaBr - */ -public class InitializationManager { - - @NotNull - private static final InitializationManager INSTANCE = new InitializationManager(); - - public static @NotNull InitializationManager getInstance() { - return INSTANCE; - } - - /** - * The list of actions to execute before creating jME context. - */ - @NotNull - private final Array onBeforeCreateJmeContext; - - /** - * The list of actions to execute after creating jME context. - */ - @NotNull - private final Array onAfterCreateJmeContext; - - /** - * The list of actions to execute before creating JavaFX context. - */ - @NotNull - private final Array onBeforeCreateJavaFxContext; - - /** - * The list of actions to execute after creating JavaFX context. - */ - @NotNull - private final Array onAfterCreateJavaFxContext; - - /** - * The list of actions to execute when the editor finish loading. - */ - @NotNull - private final Array onFinishLoading; - - private InitializationManager() { - this.onBeforeCreateJmeContext = ArrayFactory.newArray(Runnable.class); - this.onAfterCreateJmeContext = ArrayFactory.newArray(Runnable.class); - this.onBeforeCreateJavaFxContext = ArrayFactory.newArray(Runnable.class); - this.onAfterCreateJavaFxContext = ArrayFactory.newArray(Runnable.class); - this.onFinishLoading = ArrayFactory.newArray(Runnable.class); - } - - /** - * Do some things before when jME context will be created. - * - * @param runnable the action. - */ - @FromAnyThread - public synchronized void addOnBeforeCreateJmeContext(@NotNull final Runnable runnable) { - this.onBeforeCreateJmeContext.add(runnable); - } - - /** - * Do some things after when jME context was created. - * - * @param runnable the action. - */ - @FromAnyThread - public synchronized void addOnAfterCreateJmeContext(@NotNull final Runnable runnable) { - this.onAfterCreateJmeContext.add(runnable); - } - - /** - * Do some things before when JavaFX context will be created. - * - * @param runnable the action. - */ - @FromAnyThread - public synchronized void addOnBeforeCreateJavaFxContext(@NotNull final Runnable runnable) { - this.onBeforeCreateJavaFxContext.add(runnable); - } - - /** - * Do some things after when JavaFX context was created. - * - * @param runnable the action. - */ - @FromAnyThread - public synchronized void addOnAfterCreateJavaFxContext(@NotNull final Runnable runnable) { - this.onAfterCreateJavaFxContext.add(runnable); - } - - /** - * Do some things before when the editor is ready to work. - * - * @param runnable the action. - */ - @FromAnyThread - public synchronized void addOnFinishLoading(@NotNull final Runnable runnable) { - this.onFinishLoading.add(runnable); - } - - /** - * Execute all actions before when jME context will be created. - */ - @JmeThread - public synchronized void onBeforeCreateJmeContext() { - onBeforeCreateJmeContext.forEach(Runnable::run); - } - - /** - * Execute all actions after when jME context was created. - */ - @JmeThread - public synchronized void onAfterCreateJmeContext() { - onAfterCreateJmeContext.forEach(Runnable::run); - } - - /** - * Execute all actions before when JavaFX context will be created. - */ - @FxThread - public synchronized void onBeforeCreateJavaFxContext() { - onBeforeCreateJavaFxContext.forEach(Runnable::run); - } - - /** - * Execute all actions after when JavaFX context was created. - */ - @FxThread - public synchronized void onAfterCreateJavaFxContext() { - onAfterCreateJavaFxContext.forEach(Runnable::run); - } - - /** - * Execute all actions before when the editor is ready to work. - */ - @FxThread - public synchronized void onFinishLoading() { - onFinishLoading.forEach(Runnable::run); - } -} diff --git a/src/main/java/com/ss/editor/manager/JavaFxImageManager.java b/src/main/java/com/ss/editor/manager/JavaFxImageManager.java deleted file mode 100644 index b45ec551..00000000 --- a/src/main/java/com/ss/editor/manager/JavaFxImageManager.java +++ /dev/null @@ -1,475 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.rlib.common.util.FileUtils.getExtension; -import static com.ss.rlib.common.util.array.ArrayFactory.asArray; -import static java.awt.Image.SCALE_DEFAULT; -import static java.nio.file.StandardOpenOption.*; -import com.jme3.asset.AssetManager; -import com.jme3.texture.Texture; -import com.ss.editor.FileExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.Config; -import com.ss.editor.file.reader.DdsReader; -import com.ss.editor.file.reader.TgaReader; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.ChangedCurrentAssetFolderEvent; -import com.ss.editor.ui.event.impl.DeletedFileEvent; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.IntegerDictionary; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.embed.swing.SwingFXUtils; -import javafx.scene.image.Image; -import jme3tools.converters.ImageToAwt; -import org.apache.commons.io.IOUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileTime; - -/** - * The class to manage previews of images to JavaFX - * - * @author JavaSaBr - */ -public class JavaFxImageManager { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(JavaFxImageManager.class); - - @NotNull - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - @NotNull - private static final String PREVIEW_CACHE_FOLDER = "preview-cache"; - - @NotNull - private static final Array FX_FORMATS = asArray( - FileExtensions.IMAGE_PNG, - FileExtensions.IMAGE_JPG, - FileExtensions.IMAGE_JPEG, - FileExtensions.IMAGE_GIF - ); - - @NotNull - private static final Array JME_FORMATS = asArray(FileExtensions.IMAGE_BMP); - - @NotNull - private static final Array IMAGE_IO_FORMATS = asArray( - FileExtensions.IMAGE_HDR, - FileExtensions.IMAGE_TIFF); - - @NotNull - private static final Array IMAGE_FORMATS = ArrayFactory.newArray(String.class); - - /** - * The size of cached images. - */ - private static final int CACHED_IMAGES_SIZE = 30; - - static { - IMAGE_FORMATS.addAll(FX_FORMATS); - IMAGE_FORMATS.addAll(JME_FORMATS); - IMAGE_FORMATS.addAll(IMAGE_IO_FORMATS); - IMAGE_FORMATS.add(FileExtensions.IMAGE_TGA); - IMAGE_FORMATS.add(FileExtensions.IMAGE_DDS); - } - - /** - * Check the file. - * - * @param file the file - * @return true if the file is image. - */ - @FromAnyThread - public static boolean isImage(@Nullable final Path file) { - if (file == null) return false; - final String extension = getExtension(file); - return IMAGE_FORMATS.contains(extension); - } - - /** - * Check the file by the asset path. - * - * @param assetPath the asset path - * @return true if the file is image. - */ - @FromAnyThread - public static boolean isImage(@Nullable final String assetPath) { - if (assetPath == null) return false; - final String extension = getExtension(assetPath); - return IMAGE_FORMATS.contains(extension); - } - - @Nullable - private static JavaFxImageManager instance; - - @FromAnyThread - public static @NotNull JavaFxImageManager getInstance() { - if (instance == null) instance = new JavaFxImageManager(); - return instance; - } - - /** - * The cache of small images. - */ - @NotNull - private IntegerDictionary>> smallImageCache; - - /** - * The cache folder. - */ - @NotNull - private final Path cacheFolder; - - private JavaFxImageManager() { - InitializeManager.valid(getClass()); - - final Path appFolder = Config.getAppFolderInUserHome(); - - this.cacheFolder = appFolder.resolve(PREVIEW_CACHE_FOLDER); - this.smallImageCache = DictionaryFactory.newIntegerDictionary(); - - final ExecutorManager executorManager = ExecutorManager.getInstance(); - executorManager.addFxTask(() -> FX_EVENT_MANAGER.addEventHandler(DeletedFileEvent.EVENT_TYPE, - event -> processEvent((DeletedFileEvent) event))); - executorManager.addFxTask(() -> FX_EVENT_MANAGER.addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, - event -> processEvent((ChangedCurrentAssetFolderEvent) event))); - } - - /** - * Get the cache folder. - * - * @return the cache folder. - */ - @FromAnyThread - private @NotNull Path getCacheFolder() { - return cacheFolder; - } - - /** - * Get an image preview. - * - * @param file the image file. - * @param width the required width. - * @param height the required height. - * @return the image. - */ - @FxThread - public @NotNull Image getImagePreview(@Nullable final Path file, final int width, final int height) { - if (file == null || !Files.exists(file)) { - return Icons.IMAGE_512; - } - - if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { - final Image image = getFromCache(file.toString(), width, height); - if (image != null) { - return image; - } - } - - final URL url = Utils.get(file, f -> f.toUri().toURL()); - final FileTime lastModFile = Utils.get(file, f -> Files.getLastModifiedTime(f)); - - final Image image = getImagePreview(url, lastModFile, width, height); - - if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { - putImageToCache(file.toString(), image, width, height); - } - - return image; - } - - /** - * Try to get an image from the cache by path and size. - * - * @param path the path to the image. - * @param width the width. - * @param height the height. - * @return the image or null. - */ - @FxThread - private @Nullable Image getFromCache(@NotNull final String path, final int width, final int height) { - - final IntegerDictionary> heightImages = smallImageCache.get(width); - if (heightImages == null) { - return null; - } - - final ObjectDictionary images = heightImages.get(height); - if (images == null) { - return null; - } - - return images.get(path); - } - - /** - * Put the image to the cache. - * - * @param path the ath to the image. - * @param image the image. - * @param width the width. - * @param height the height. - */ - @FxThread - private void putImageToCache(@NotNull final String path, @NotNull final Image image, final int width, - final int height) { - smallImageCache.get(width, DictionaryFactory::newIntegerDictionary) - .get(height, DictionaryFactory::newObjectDictionary) - .put(path, image); - } - - /** - * Get an image preview. - * - * @param resourcePath the resource path to an image. - * @param width the required width. - * @param height the required height. - * @return the image. - */ - @FxThread - public @NotNull Image getImagePreview(@Nullable final String resourcePath, final int width, final int height) { - - if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { - final Image image = getFromCache(resourcePath, width, height); - if (image != null) { - return image; - } - } - - final ResourceManager resourceManager = ResourceManager.getInstance(); - URL url = resourceManager.tryToFindResource(resourcePath); - - if (url == null) { - - final Path realFile = EditorUtil.getRealFile(resourcePath); - if (realFile == null || !Files.exists(realFile)) { - return Icons.IMAGE_512; - } - - url = FileUtils.toUrl(realFile); - } - - final Image image = getImagePreview(url, null, width, height); - - if (width <= CACHED_IMAGES_SIZE && height <= CACHED_IMAGES_SIZE) { - putImageToCache(resourcePath, image, width, height); - } - - return image; - } - - @FxThread - private @NotNull Image getImagePreview(@NotNull URL url, @Nullable final FileTime lastModFile, final int width, - final int height) { - - final String externalForm = url.toExternalForm(); - final String fileHash = StringUtils.toMD5(externalForm) + ".png"; - - final Path cacheFolder = getCacheFolder(); - final Path imageFolder = cacheFolder.resolve(String.valueOf(width)).resolve(String.valueOf(height)); - final Path cacheFile = imageFolder.resolve(fileHash); - - if (Files.exists(cacheFile)) { - - final FileTime lastModCacheFile = Utils.get(cacheFile, file -> Files.getLastModifiedTime(file)); - - if (lastModFile == null || lastModCacheFile.compareTo(lastModFile) >= 0) { - final String pathToCache = Utils.get(cacheFile, first -> first.toUri().toURL().toExternalForm()); - return new Image(pathToCache, width, height, false, false); - } - } - - Utils.run(cacheFile, first -> Files.createDirectories(first.getParent())); - - final String extension = getExtension(externalForm); - - if (FX_FORMATS.contains(extension)) { - return readFxImage(width, height, externalForm, cacheFile); - } else if (JME_FORMATS.contains(extension)) { - return readJMETexture(width, height, externalForm, cacheFile); - } else if (IMAGE_IO_FORMATS.contains(extension)) { - return readIOImage(url, width, height, cacheFile); - } else if (FileExtensions.IMAGE_DDS.equals(extension)) { - - final byte[] content = Utils.get(url, first -> IOUtils.toByteArray(first.openStream())); - final int[] pixels = DdsReader.read(content, DdsReader.ARGB, 0); - final int currentWidth = DdsReader.getWidth(content); - final int currentHeight = DdsReader.getHeight(content); - - final BufferedImage read = new BufferedImage(currentWidth, currentHeight, BufferedImage.TYPE_INT_ARGB); - read.setRGB(0, 0, currentWidth, currentHeight, pixels, 0, currentWidth); - - return scaleAndWrite(width, height, cacheFile, read, currentWidth, currentHeight); - - } else if (FileExtensions.IMAGE_TGA.equals(extension)) { - - final byte[] content = Utils.get(url, first -> IOUtils.toByteArray(first.openStream())); - final BufferedImage awtImage; - try { - awtImage = (BufferedImage) TgaReader.getImage(content); - } catch (final Exception e) { - LOGGER.warning(e); - writeDefaultToCache(cacheFile); - return Icons.IMAGE_512; - } - - final int imageWidth = awtImage.getWidth(); - final int imageHeight = awtImage.getHeight(); - - return scaleAndWrite(width, height, cacheFile, awtImage, imageWidth, imageHeight); - } - - return Icons.IMAGE_512; - } - - @FxThread - private void writeDefaultToCache(@NotNull final Path cacheFile) { - final BufferedImage bufferedImage = SwingFXUtils.fromFXImage(Icons.IMAGE_512, null); - try (final OutputStream out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - ImageIO.write(bufferedImage, "png", out); - } catch (final IOException ex) { - LOGGER.warning(ex); - } - } - - @FxThread - private @NotNull Image readIOImage(@NotNull final URL url, final int width, final int height, - @NotNull final Path cacheFile) { - - final BufferedImage read; - try { - read = ImageIO.read(url); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return Icons.IMAGE_512; - } - - return scaleAndWrite(width, height, cacheFile, read, read.getWidth(), read.getHeight()); - } - - @FxThread - private @NotNull Image readJMETexture(final int width, final int height, @NotNull final String externalForm, - @NotNull final Path cacheFile) { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Texture texture = assetManager.loadTexture(externalForm); - - final BufferedImage textureImage; - try { - textureImage = ImageToAwt.convert(texture.getImage(), false, true, 0); - } catch (final UnsupportedOperationException e) { - EditorUtil.handleException(LOGGER, this, e); - return Icons.IMAGE_512; - } - - final int imageWidth = textureImage.getWidth(); - final int imageHeight = textureImage.getHeight(); - - return scaleAndWrite(width, height, cacheFile, textureImage, imageWidth, imageHeight); - } - - @FxThread - private @NotNull Image readFxImage(final int width, final int height, @NotNull final String externalForm, - @NotNull final Path cacheFile) { - - Image image = new Image(externalForm); - - final int imageWidth = (int) image.getWidth(); - final int imageHeight = (int) image.getHeight(); - - if (imageWidth > width || imageHeight > height) { - if (imageWidth == imageHeight) { - image = new Image(externalForm, width, height, false, false); - } else if (imageWidth > imageHeight) { - float mod = imageHeight * 1F / imageWidth; - image = new Image(externalForm, width, height * mod, false, false); - } else if (imageHeight > imageWidth) { - float mod = imageWidth * 1F / imageHeight; - image = new Image(externalForm, width * mod, height, false, false); - } - } - - final BufferedImage bufferedImage = SwingFXUtils.fromFXImage(image, null); - - try (final OutputStream out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - ImageIO.write(bufferedImage, "png", out); - } catch (final IOException e) { - LOGGER.warning(e); - } - - return image; - } - - @FxThread - private @NotNull Image scaleAndWrite(final int targetWidth, final int targetHeight, @NotNull final Path cacheFile, - @NotNull final BufferedImage textureImage, final int currentWidth, - final int currentHeight) { - - final BufferedImage newImage = scaleImage(targetWidth, targetHeight, textureImage, currentWidth, currentHeight); - - try (final OutputStream out = Files.newOutputStream(cacheFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - ImageIO.write(newImage, "png", out); - return new Image(cacheFile.toUri().toString()); - } catch (final IOException e) { - LOGGER.warning(e); - return Icons.IMAGE_512; - } - } - - @FxThread - private @NotNull BufferedImage scaleImage(final int width, final int height, @NotNull final BufferedImage read, - final int imageWidth, final int imageHeight) { - - java.awt.Image newImage = read; - - if (imageWidth > width || imageHeight > height) { - if (imageWidth == imageHeight) { - newImage = read.getScaledInstance(width, height, SCALE_DEFAULT); - } else if (imageWidth > imageHeight) { - float mod = imageHeight * 1F / imageWidth; - newImage = read.getScaledInstance(width, (int) (height * mod), SCALE_DEFAULT); - } else if (imageHeight > imageWidth) { - float mod = imageWidth * 1F / imageHeight; - newImage = read.getScaledInstance((int) (width * mod), height, SCALE_DEFAULT); - } - } - - final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - - final Graphics2D g2d = bufferedImage.createGraphics(); - g2d.drawImage(newImage, 0, 0, null); - g2d.dispose(); - - return bufferedImage; - } - - @FxThread - private void processEvent(@NotNull final DeletedFileEvent event) { - //TODO need to add remove from cache - } - - @FxThread - private void processEvent(@NotNull final ChangedCurrentAssetFolderEvent event) { - smallImageCache.clear(); - } -} diff --git a/src/main/java/com/ss/editor/manager/PluginManager.java b/src/main/java/com/ss/editor/manager/PluginManager.java deleted file mode 100644 index 31f36735..00000000 --- a/src/main/java/com/ss/editor/manager/PluginManager.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.rlib.common.plugin.impl.PluginSystemFactory.newBasePluginSystem; -import com.jme3.asset.AssetManager; -import com.ss.editor.JmeApplication; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.Config; -import com.ss.editor.plugin.EditorPlugin; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.plugin.ConfigurablePluginSystem; -import com.ss.rlib.common.plugin.Plugin; -import com.ss.rlib.common.plugin.PluginContainer; -import com.ss.rlib.common.plugin.exception.PreloadPluginException; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.function.Consumer; - -/** - * The manager to work with plugins. - * - * @author JavaSaBr - */ -public class PluginManager { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(PluginManager.class); - - @Nullable - private static PluginManager instance; - - @NotNull - public static PluginManager getInstance() { - if (instance == null) instance = new PluginManager(); - return instance; - } - - /** - * The plugin system. - */ - @NotNull - private final ConfigurablePluginSystem pluginSystem; - - private PluginManager() { - InitializeManager.valid(getClass()); - - this.pluginSystem = newBasePluginSystem(getClass().getClassLoader()); - this.pluginSystem.setAppVersion(Config.APP_VERSION); - - var folderInUserHome = Config.getAppFolderInUserHome(); - var embeddedPath = System.getProperty("editor.embedded.plugins.path"); - - if (embeddedPath != null && Files.exists(Paths.get(embeddedPath))) { - var embeddedPluginPath = Paths.get(embeddedPath); - LOGGER.debug(this, "embedded plugin path: " + embeddedPluginPath); - pluginSystem.configureEmbeddedPluginPath(embeddedPluginPath); - } else { - var rootFolder = Utils.getRootFolderFromClass(JmeApplication.class); - var embeddedPluginPath = rootFolder.resolve("embedded-plugins"); - LOGGER.debug(this, "embedded plugin path: " + embeddedPluginPath); - if (Files.exists(embeddedPluginPath)) { - pluginSystem.configureEmbeddedPluginPath(embeddedPluginPath); - } else { - LOGGER.warning(this, "The embedded plugin folder doesn't exists."); - } - } - - var userPluginsFolder = folderInUserHome.resolve("plugins"); - - LOGGER.debug(this, "installation plugin path: " + userPluginsFolder); - - if (!Files.exists(userPluginsFolder)) { - FileUtils.createDirectories(userPluginsFolder); - } - - pluginSystem.configureInstallationPluginsPath(userPluginsFolder); - - try { - pluginSystem.preLoad(); - } catch (PreloadPluginException e) { - FileUtils.delete(e.getPath()); - throw e; - } - - pluginSystem.initialize(); - - var initManager = InitializationManager.getInstance(); - initManager.addOnBeforeCreateJmeContext(this::onBeforeCreateJmeContext); - initManager.addOnAfterCreateJmeContext(this::onAfterCreateJmeContext); - initManager.addOnBeforeCreateJavaFxContext(this::onBeforeCreateJavaFxContext); - initManager.addOnAfterCreateJavaFxContext(this::onAfterCreateJavaFxContext); - initManager.addOnFinishLoading(this::onFinishLoading); - } - - /** - * Install a new plugin to the system. - * - * @param path the path to the plugin. - */ - public void installPlugin(@NotNull Path path) { - pluginSystem.installPlugin(path, false); - } - - /** - * Remove a plugin from this editor. - * - * @param plugin the plugin. - */ - public void removePlugin(@NotNull EditorPlugin plugin) { - pluginSystem.removePlugin(plugin); - } - - /** - * Do some things before when JME context will be created. - */ - @JmeThread - private void onBeforeCreateJmeContext() { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(editorPlugin -> editorPlugin.onBeforeCreateJmeContext(pluginSystem)); - } - - /** - * Do some things after when JME context was created. - */ - @JmeThread - private void onAfterCreateJmeContext() { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(editorPlugin -> { - - editorPlugin.onAfterCreateJmeContext(pluginSystem); - - var container = editorPlugin.getContainer(); - var classLoader = container.getClassLoader(); - var assetManager = EditorUtil.getAssetManager(); - assetManager.addClassLoader(classLoader); - }); - } - - /** - * Do some things before when JavaFX context will be created. - */ - @FxThread - private void onBeforeCreateJavaFxContext() { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(editorPlugin -> editorPlugin.onBeforeCreateJavaFxContext(pluginSystem)); - } - - /** - * Do some things after when JavaFX context was created. - */ - @FxThread - private void onAfterCreateJavaFxContext() { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(editorPlugin -> editorPlugin.onAfterCreateJavaFxContext(pluginSystem)); - } - - /** - * Do some things before when the editor is ready to work. - */ - @FxThread - private void onFinishLoading() { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(editorPlugin -> editorPlugin.onFinishLoading(pluginSystem)); - } - - /** - * Handle each loaded plugin. - * - * @param consumer the consumer. - */ - @FromAnyThread - public void handlePlugins(@NotNull Consumer consumer) { - pluginSystem.getPlugins().stream() - .filter(EditorPlugin.class::isInstance) - .map(EditorPlugin.class::cast) - .forEach(consumer); - } -} diff --git a/src/main/java/com/ss/editor/manager/RemoteControlManager.java b/src/main/java/com/ss/editor/manager/RemoteControlManager.java deleted file mode 100644 index cfccda3f..00000000 --- a/src/main/java/com/ss/editor/manager/RemoteControlManager.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.ss.editor.manager; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.Config; -import com.ss.editor.manager.ClasspathManager.Scope; -import com.ss.rlib.common.network.NetworkConfig; -import com.ss.rlib.common.network.NetworkFactory; -import com.ss.rlib.common.network.packet.ReadablePacket; -import com.ss.rlib.common.network.packet.ReadablePacketRegistry; -import com.ss.rlib.common.network.server.AcceptHandler; -import com.ss.rlib.common.network.server.ServerNetwork; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.net.InetSocketAddress; - -/** - * The manager to process remote control. - * - * @author JavaSaBr - */ -public class RemoteControlManager { - - @NotNull - private static final NetworkConfig NETWORK_CONFIG = new NetworkConfig() { - - @Override - public int getReadBufferSize() { - return Short.MAX_VALUE * 2; - } - - @Override - public int getWriteBufferSize() { - return Short.MAX_VALUE * 2; - } - }; - - @Nullable - private static RemoteControlManager instance; - - public static @NotNull RemoteControlManager getInstance() { - if (instance == null) instance = new RemoteControlManager(); - return instance; - } - - @NotNull - private final ReadablePacketRegistry packetRegistry; - - @Nullable - private volatile ServerNetwork serverNetwork; - - private RemoteControlManager() { - - final ClasspathManager classpathManager = ClasspathManager.getInstance(); - final Class[] packets = classpathManager.findImplements(ReadablePacket.class, Scope.ONLY_CORE) - .toArray(Class.class); - - this.packetRegistry = ReadablePacketRegistry.of(packets); - - final InitializationManager initializationManager = InitializationManager.getInstance(); - initializationManager.addOnAfterCreateJmeContext(this::start); - } - - /** - * Start the remote control if need. - */ - @FromAnyThread - private synchronized void start() { - - if (Config.REMOTE_CONTROL_PORT == -1) { - return; - } - - serverNetwork = NetworkFactory.newDefaultAsyncServerNetwork(NETWORK_CONFIG, packetRegistry, AcceptHandler.newDefault()); - try { - serverNetwork.bind(new InetSocketAddress(Config.REMOTE_CONTROL_PORT)); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/com/ss/editor/manager/ResourceManager.java b/src/main/java/com/ss/editor/manager/ResourceManager.java deleted file mode 100644 index f7aa52db..00000000 --- a/src/main/java/com/ss/editor/manager/ResourceManager.java +++ /dev/null @@ -1,685 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.editor.FileExtensions.*; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_FAST_SKY_FOLDER; -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.rlib.common.util.ArrayUtils.contains; -import static com.ss.rlib.common.util.FileUtils.getFiles; -import static com.ss.rlib.common.util.FileUtils.toUrl; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.Utils.get; -import static com.ss.rlib.common.util.array.ArrayFactory.toArray; -import static com.ss.rlib.common.util.ref.ReferenceFactory.newRef; -import static java.lang.System.currentTimeMillis; -import static java.nio.file.StandardWatchEventKinds.*; -import com.jme3.asset.AssetEventListener; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.ss.editor.EditorThread; -import com.ss.editor.FileExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.*; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.SimpleFileVisitor; -import com.ss.editor.util.SimpleFolderVisitor; -import com.ss.rlib.common.concurrent.util.ThreadUtils; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayComparator; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import com.ss.rlib.common.util.ref.Reference; -import com.ss.rlib.common.util.ref.ReferenceType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.*; -import java.nio.file.attribute.FileTime; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * The class to manage working with resources of an editor. - * - * @author JavaSaBr - */ -public class ResourceManager extends EditorThread implements AssetEventListener { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(ResourceManager.class); - - @NotNull - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - @NotNull - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - @NotNull - private static final ArrayComparator STRING_ARRAY_COMPARATOR = StringUtils::compareIgnoreCase; - - @NotNull - private static final WatchService WATCH_SERVICE; - - static { - try { - WATCH_SERVICE = FileSystems.getDefault().newWatchService(); - } catch (final IOException e) { - LOGGER.warning(e); - throw new RuntimeException(e); - } - } - - @Nullable - private static ResourceManager instance; - - @FromAnyThread - public static @NotNull ResourceManager getInstance() { - if (instance == null) instance = new ResourceManager(); - return instance; - } - - /** - * The table with last modify dates. - */ - @NotNull - private final ObjectDictionary assetCacheTable; - - /** - * The table with interested resources. - */ - @NotNull - private final ObjectDictionary> interestedResources; - - /** - * The table with interested resources in the classpath. - */ - @NotNull - private final ObjectDictionary> interestedResourcesInClasspath; - - /** - * The list of additional ENVs. - */ - @NotNull - private final Array additionalEnvs; - - /** - * The list of an additional classpath. - */ - @NotNull - private final Array classLoaders; - - /** - * The list of resources in the classpath. - */ - @NotNull - private final Array resourcesInClasspath; - - /** - * The list of keys for watching to folders. - */ - @NotNull - private final Array watchKeys; - - private ResourceManager() { - InitializeManager.valid(getClass()); - - final ClasspathManager classpathManager = ClasspathManager.getInstance(); - - this.assetCacheTable = DictionaryFactory.newObjectDictionary(); - this.additionalEnvs = ArrayFactory.newArray(Path.class); - this.watchKeys = ArrayFactory.newArray(WatchKey.class); - this.classLoaders = ArrayFactory.newArray(URLClassLoader.class); - this.resourcesInClasspath = classpathManager.getAllResources(); - this.interestedResources = DictionaryFactory.newObjectDictionary(); - this.interestedResourcesInClasspath = DictionaryFactory.newObjectDictionary(); - - final InitializationManager initializationManager = InitializationManager.getInstance(); - initializationManager.addOnFinishLoading(() -> { - prepareClasspathResources(); - final FxEventManager fxEventManager = FxEventManager.getInstance(); - fxEventManager.addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, event -> processChangeAsset()); - fxEventManager.addEventHandler(RequestedRefreshAssetEvent.EVENT_TYPE, event -> processRefreshAsset()); - fxEventManager.addEventHandler(CreatedFileEvent.EVENT_TYPE, event -> processEvent((CreatedFileEvent) event)); - fxEventManager.addEventHandler(DeletedFileEvent.EVENT_TYPE, event -> processEvent((DeletedFileEvent) event)); - }); - - initializationManager.addOnAfterCreateJmeContext(() -> { - final AssetManager assetManager = EditorUtil.getAssetManager(); - assetManager.addAssetEventListener(this); - }); - - registerInterestedFileType(FileExtensions.JME_MATERIAL_DEFINITION); - updateAdditionalEnvs(); - start(); - } - - /** - * Try to find a resource by the resource path. - * - * @param resourcePath the resource path. - * @return the URL or null. - */ - @FromAnyThread - public @Nullable URL tryToFindResource(@NotNull final String resourcePath) { - - final Array<@NotNull ClassLoader> classLoaders = ArrayFactory.newArray(ClassLoader.class); - classLoaders.add(getClass().getClassLoader()); - - final ClasspathManager classpathManager = ClasspathManager.getInstance(); - final URLClassLoader classesLoader = classpathManager.getClassesLoader(); - final URLClassLoader librariesLoader = classpathManager.getLibrariesLoader(); - - if (classesLoader != null) { - classLoaders.add(classesLoader); - } - - if (librariesLoader != null) { - classLoaders.add(librariesLoader); - } - - final PluginManager pluginManager = PluginManager.getInstance(); - pluginManager.handlePlugins(plugin -> classLoaders.add(plugin.getClassLoader())); - - final String altResourcePath = "/" + resourcePath; - - URL url = null; - - for (final ClassLoader classLoader : classLoaders) { - url = classLoader.getResource(resourcePath); - if (url != null) break; - url = classLoader.getResource(altResourcePath); - if (url != null) break; - } - - if (url == null) { - url = getClass().getResource("/" + resourcePath); - } - - return url; - } - - /** - * @return the table with interested resources. - */ - @FromAnyThread - private @NotNull ObjectDictionary> getInterestedResources() { - return interestedResources; - } - - /** - * @return the table with interested resources in the classpath. - */ - @FromAnyThread - private @NotNull ObjectDictionary> getInterestedResourcesInClasspath() { - return interestedResourcesInClasspath; - } - - /** - * Register the file type of interested resources. - * - * @param fileExtension the file type. - */ - @FromAnyThread - public synchronized void registerInterestedFileType(@NotNull final String fileExtension) { - - ObjectDictionary> resources = getInterestedResources(); - - if(!resources.containsKey(fileExtension)) { - resources.put(fileExtension, ArrayFactory.newArray(String.class)); - } - - resources = getInterestedResourcesInClasspath(); - - if(!resources.containsKey(fileExtension)) { - resources.put(fileExtension, ArrayFactory.newArray(String.class)); - } - } - - @Override - @FromAnyThread - public synchronized void assetLoaded(@NotNull final AssetKey key) { - - if (key.getCacheType() == null) { - return; - } - - final String extension = key.getExtension(); - if (StringUtils.isEmpty(extension)) { - return; - } - - final ObjectDictionary table = getAssetCacheTable(); - final Reference reference = notNull(table.get(key.getName(), () -> newRef(ReferenceType.LONG))); - reference.setLong(currentTimeMillis()); - } - - @Override - @FromAnyThread - public synchronized void assetRequested(@NotNull final AssetKey key) { - - if (key.getCacheType() == null) { - return; - } - - final String extension = key.getExtension(); - if (StringUtils.isEmpty(extension)){ - return; - } - - final ObjectDictionary table = getAssetCacheTable(); - final Reference reference = table.get(key.getName()); - if (reference == null) { - return; - } - - final Path realFile = getRealFile(Paths.get(key.getName())); - if (realFile == null || !Files.exists(realFile)) { - return; - } - - try { - - final long timestamp = reference.getLong(); - - final FileTime lastModifiedTime = Files.getLastModifiedTime(realFile); - if (lastModifiedTime.to(TimeUnit.MILLISECONDS) <= timestamp) { - return; - } - - final AssetManager assetManager = EditorUtil.getAssetManager(); - assetManager.deleteFromCache(key); - - } catch (final IOException e) { - LOGGER.warning(e); - } - } - - @Override - @FromAnyThread - public void assetDependencyNotFound(@NotNull final AssetKey parentKey, @NotNull final AssetKey dependentAssetKey) { - } - - /** - * Update the list with additional ENVs. - */ - @FromAnyThread - public synchronized void updateAdditionalEnvs() { - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Array additionalEnvs = getAdditionalEnvs(); - additionalEnvs.clear(); - - final Path folder = editorConfig.getFile(PREF_FAST_SKY_FOLDER); - if (folder == null) { - return; - } - - additionalEnvs.addAll(getFiles(folder, IMAGE_HDR, IMAGE_TGA, IMAGE_PNG)); - } - - /** - * Get a list with additional ENVs. - * - * @return the list. - */ - @FromAnyThread - public @NotNull Array getAdditionalEnvs() { - return additionalEnvs; - } - - /** - * @return the table with last modify dates. - */ - @FromAnyThread - private @NotNull ObjectDictionary getAssetCacheTable() { - return assetCacheTable; - } - - /** - * Handle a removed file. - */ - @FromAnyThread - private synchronized void processEvent(@NotNull final DeletedFileEvent event) { - - if (event.isDirectory()) { - return; - } - - final Path file = event.getFile(); - final String extension = FileUtils.getExtension(file); - - final ObjectDictionary> interestedResources = getInterestedResources(); - final Array resources = interestedResources.get(extension); - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - if (resources != null) { - resources.fastRemove(assetPath); - } - - if (extension.endsWith(FileExtensions.JAVA_LIBRARY)) { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - final URL url = toUrl(file); - final Array classLoaders = getClassLoaders(); - - final URLClassLoader oldLoader = classLoaders.search(url, (loader, toCheck) -> contains(loader.getURLs(), toCheck)); - - if (oldLoader != null) { - classLoaders.fastRemove(oldLoader); - assetManager.removeClassLoader(oldLoader); - } - } - } - - /** - * Handle a created file. - */ - @FromAnyThread - private synchronized void processEvent(@NotNull final CreatedFileEvent event) { - if (event.isDirectory()) return; - handleFile(event.getFile()); - } - - /** - * @return the list of resources in the classpath. - */ - @FromAnyThread - private @NotNull Array getResourcesInClasspath() { - return resourcesInClasspath; - } - - /** - * Prepare classpath resources. - */ - @FromAnyThread - private void prepareClasspathResources() { - - final ObjectDictionary> resources = getInterestedResourcesInClasspath(); - final Array resourcesInClasspath = getResourcesInClasspath(); - resourcesInClasspath.forEach(resource -> { - final String extension = FileUtils.getExtension(resource); - final Array toStore = resources.get(extension); - if (toStore != null) { - toStore.add(resource); - } - }); - } - - /** - * Gets class loaders. - * - * @return the list of an additional classpath. - */ - @FromAnyThread - public @NotNull Array getClassLoaders() { - return classLoaders; - } - - /** - * Get available resources by the file extension. - * - * @param extension the interested extension. - * @return the list of all available material definitions. - */ - @FromAnyThread - public synchronized @NotNull Array getAvailableResources(@NotNull final String extension) { - final Array result = ArrayFactory.newArray(String.class); - addAvailableResources(result, extension); - return result; - } - - /** - * Add available interested resources to the result array by the file extension. - * - * @param result the array to store result. - * @param extension the interested extension. - */ - @FromAnyThread - public synchronized void addAvailableResources(@NotNull final Array result, - @NotNull final String extension) { - - final ObjectDictionary> resourcesInClasspath = getInterestedResourcesInClasspath(); - final ObjectDictionary> resources = getInterestedResources(); - - final Array inAsset = resources.get(extension); - final Array inClassPath = resourcesInClasspath.get(extension); - - if (inAsset != null) { - result.addAll(inAsset); - } - - if (inClassPath != null) { - inClassPath.forEach(result, - (resource, toStore) -> !toStore.contains(resource), - (resource, toStore) -> toStore.add(resource)); - } - - result.sort(STRING_ARRAY_COMPARATOR); - } - - /** - * Reload available resources. - */ - @FromAnyThread - public synchronized void reload() { - - final ObjectDictionary lastModifyTable = getAssetCacheTable(); - lastModifyTable.clear(); - - final Array watchKeys = getWatchKeys(); - watchKeys.forEach(WatchKey::cancel); - watchKeys.clear(); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - final Array classLoaders = getClassLoaders(); - classLoaders.forEach(assetManager, (loader, manager) -> manager.removeClassLoader(loader)); - classLoaders.clear(); - - assetManager.clearCache(); - - final ObjectDictionary> interestedResources = getInterestedResources(); - interestedResources.forEach((extension, resources) -> resources.clear()); - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Path currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) return; - - try { - Files.walkFileTree(currentAsset, (SimpleFileVisitor) (file, attrs) -> handleFile(file)); - } catch (IOException e) { - LOGGER.warning(e); - } - - try { - watchKeys.add(currentAsset.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY)); - Files.walkFileTree(currentAsset, (SimpleFolderVisitor) (file, attrs) -> registerFiles(watchKeys, file)); - } catch (final IOException e) { - LOGGER.warning(e); - } - } - - @FromAnyThread - private static void registerFiles(@NotNull final Array watchKeys, @NotNull final Path file) { - watchKeys.add(get(file, toRegister -> toRegister.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY))); - } - - /** - * Handle a file event in an asset folder. - */ - @FromAnyThread - private synchronized void handleFile(@NotNull final Path file) { - - if (Files.isDirectory(file)) { - return; - } - - final String extension = FileUtils.getExtension(file); - - final ObjectDictionary> interestedResources = getInterestedResources(); - final Array toStore = interestedResources.get(extension); - - if (toStore != null) { - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - toStore.add(toAssetPath(assetFile)); - } - - if (extension.endsWith(FileExtensions.JAVA_LIBRARY)) { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final URL url = get(file, FileUtils::toUrl); - - final Array classLoaders = getClassLoaders(); - final URLClassLoader oldLoader = classLoaders.search(url, (loader, toCheck) -> contains(loader.getURLs(), toCheck)); - if (oldLoader != null) return; - - final URLClassLoader newLoader = new URLClassLoader(toArray(url), getClass().getClassLoader()); - classLoaders.add(newLoader); - assetManager.addClassLoader(newLoader); - } - } - - @Override - public void run() { - super.run(); - - while (true) { - ThreadUtils.sleep(200); - - final Array watchKeys = getWatchKeys(); - - List> watchEvents = null; - WatchKey watchKey = null; - - synchronized (this) { - for (final WatchKey key : watchKeys) { - watchKey = key; - watchEvents = key.pollEvents(); - if (!watchEvents.isEmpty()) break; - } - } - - if (watchEvents == null || watchEvents.isEmpty()) continue; - - for (final WatchEvent watchEvent : watchEvents) { - - final Path file = (Path) watchEvent.context(); - final Path folder = (Path) watchKey.watchable(); - final Path realFile = folder.resolve(file); - - if (watchEvent.kind() == ENTRY_CREATE) { - - final boolean directory = Files.isDirectory(realFile); - - final CreatedFileEvent event = new CreatedFileEvent(); - event.setFile(realFile); - event.setNeedSelect(false); - event.setDirectory(directory); - - if (directory) { - registerWatchKey(realFile); - } - - FX_EVENT_MANAGER.notify(event); - - } else if (watchEvent.kind() == ENTRY_DELETE) { - - final boolean directory = Files.isDirectory(realFile); - - final DeletedFileEvent event = new DeletedFileEvent(); - event.setFile(realFile); - event.setDirectory(directory); - - removeWatchKeyFor(realFile); - - FX_EVENT_MANAGER.notify(event); - - } else if (watchEvent.kind() == ENTRY_MODIFY) { - - final FileChangedEvent event = new FileChangedEvent(); - event.setFile(realFile); - - FX_EVENT_MANAGER.notify(event); - } - } - } - } - - /** - * Find a watch key for the file. - * - * @param path the file. - * @return the watch key or null. - */ - @FromAnyThread - private synchronized @Nullable WatchKey findWatchKey(@NotNull final Path path) { - final Array watchKeys = getWatchKeys(); - return watchKeys.search(path, (watchKey, toCheck) -> watchKey.watchable().equals(toCheck)); - } - - /** - * Remove a watch key for the file. - * - * @param path the file. - */ - @FromAnyThread - private synchronized void removeWatchKeyFor(@NotNull final Path path) { - - final WatchKey watchKey = findWatchKey(path); - if (watchKey == null) { - return; - } - - final Array watchKeys = getWatchKeys(); - watchKeys.fastRemove(watchKey); - watchKey.cancel(); - } - - /** - * Register a watch key for the file. - * - * @param path the file. - */ - @FromAnyThread - private synchronized void registerWatchKey(@NotNull final Path path) { - Utils.run(() -> getWatchKeys().add(path.register(WATCH_SERVICE, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY))); - } - - /** - * Handle refreshing asset folder. - */ - @FromAnyThread - private void processRefreshAsset() { - EXECUTOR_MANAGER.addBackgroundTask(this::reload); - } - - /** - * Handle changing asset folder. - */ - @FromAnyThread - private void processChangeAsset() { - EXECUTOR_MANAGER.addBackgroundTask(this::reload); - } - - /** - * @return the list of keys for watching to folders. - */ - @FromAnyThread - private @NotNull Array getWatchKeys() { - return watchKeys; - } -} diff --git a/src/main/java/com/ss/editor/manager/WorkspaceManager.java b/src/main/java/com/ss/editor/manager/WorkspaceManager.java deleted file mode 100644 index ab3bb7cc..00000000 --- a/src/main/java/com/ss/editor/manager/WorkspaceManager.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.ss.editor.manager; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.Utils.get; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.model.workspace.Workspace; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import com.ss.rlib.common.manager.InitializeManager; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; - -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The class to manage workspaces. - * - * @author JavaSaBr - */ -public class WorkspaceManager { - - /** - * The constant FOLDER_EDITOR. - */ - @NotNull - public static final String FOLDER_EDITOR = ".jmonkeybuilder"; - - /** - * The constant FILE_WORKSPACE. - */ - @NotNull - public static final String FILE_WORKSPACE = "workspace"; - - @Nullable - private static WorkspaceManager instance; - - @FromAnyThread - public static @NotNull WorkspaceManager getInstance() { - if (instance == null) instance = new WorkspaceManager(); - return instance; - } - - /** - * The table of workspaces. - */ - @NotNull - private final ObjectDictionary workspaces; - - private WorkspaceManager() { - InitializeManager.valid(getClass()); - this.workspaces = DictionaryFactory.newObjectDictionary(); - } - - /** - * Get the table of workspaces. - * - * @return the table of workspaces. - */ - @FromAnyThread - private @NotNull ObjectDictionary getWorkspaces() { - return workspaces; - } - - /** - * Get the current workspace. - * - * @return the current workspace or null. - */ - @FromAnyThread - public @Nullable Workspace getCurrentWorkspace() { - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Path currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) return null; - return getWorkspace(currentAsset); - } - - /** - * Get the workspace for the asset folder. - * - * @return the workspace. - */ - @FromAnyThread - private synchronized @NotNull Workspace getWorkspace(@NotNull final Path assetFolder) { - - final ObjectDictionary workspaces = getWorkspaces(); - final Workspace exists = workspaces.get(assetFolder); - if (exists != null) return exists; - - final Path workspaceFile = assetFolder.resolve(FOLDER_EDITOR).resolve(FILE_WORKSPACE); - - if (!Files.exists(workspaceFile)) { - - final Workspace workspace = new Workspace(); - workspace.notifyRestored(); - workspace.setAssetFolder(assetFolder); - workspaces.put(assetFolder, workspace); - - return workspace; - } - - Workspace workspace; - try { - workspace = EditorUtil.deserialize(notNull(get(workspaceFile, Files::readAllBytes))); - } catch (final RuntimeException e) { - workspace = new Workspace(); - } - - workspace.notifyRestored(); - workspace.setAssetFolder(assetFolder); - workspaces.put(assetFolder, workspace); - - return workspace; - } - - /** - * Clear all workspaces. - */ - @FromAnyThread - public synchronized void clear() { - final ObjectDictionary workspaces = getWorkspaces(); - workspaces.forEach(Workspace::clear); - workspaces.forEach((path, workspace) -> workspace.save(true)); - } - - /** - * Save all workspaces. - */ - @FromAnyThread - public synchronized void save() { - getWorkspaces().forEach((path, workspace) -> workspace.save(true)); - } -} diff --git a/src/main/java/com/ss/editor/model/EditorCamera.java b/src/main/java/com/ss/editor/model/EditorCamera.java deleted file mode 100644 index 2514eccf..00000000 --- a/src/main/java/com/ss/editor/model/EditorCamera.java +++ /dev/null @@ -1,1008 +0,0 @@ -package com.ss.editor.model; - -import static com.ss.rlib.common.geom.util.AngleUtils.degreeToRadians; -import static com.ss.rlib.common.geom.util.AngleUtils.radiansToDegree; -import static java.lang.Math.*; -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.input.*; -import com.jme3.input.controls.ActionListener; -import com.jme3.input.controls.AnalogListener; -import com.jme3.input.controls.MouseAxisTrigger; -import com.jme3.input.controls.MouseButtonTrigger; -import com.jme3.math.FastMath; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.config.Config; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; - -/** - * The implementation of editor camera based on {@link ChaseCamera}. - * - * @author JavaSaBr - */ -public class EditorCamera implements ActionListener, AnalogListener, Control { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(EditorCamera.class); - - private static final String CHASECAM_TOGGLEROTATE = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_TOGGLEROTATE; - private static final String CHASECAM_DOWN = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_DOWN; - private static final String CHASECAM_UP = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_UP; - private static final String CHASECAM_MOVELEFT = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_MOVELEFT; - private static final String CHASECAM_MOVERIGHT = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_MOVERIGHT; - private static final String CHASECAM_ZOOMIN = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_ZOOMIN; - private static final String CHASECAM_ZOOMOUT = EditorCamera.class.getSimpleName() + "_" + CameraInput.CHASECAM_ZOOMOUT; - - private static final String[] ALL_INPUTS = { - CHASECAM_TOGGLEROTATE, - CHASECAM_DOWN, - CHASECAM_UP, - CHASECAM_MOVELEFT, - CHASECAM_MOVERIGHT, - CHASECAM_ZOOMIN, - CHASECAM_ZOOMOUT - }; - - /** - * The enum Perspective. - */ - public enum Perspective { - /** - * Back perspective. - */ - BACK, - /** - * Right perspective. - */ - RIGHT, - /** - * Top perspective. - */ - TOP, - /** - * Bottom perspective. - */ - BOTTOM - } - - /** - * The enum Direction. - */ - public enum Direction { - /** - * Left direction. - */ - LEFT, - /** - * Right direction. - */ - RIGHT, - /** - * Top direction. - */ - TOP, - /** - * Bottom direction. - */ - BOTTOM - } - - private InputManager inputManager; - - private final Camera camera; - - private Spatial target; - - private final Vector3f targetDir; - private final Vector3f position; - - private final Vector3f targetLocation; - private final Vector3f temp; - - private Vector3f initialUpVec; - private Vector3f prevPos; - private Vector3f lookAtOffset; - - private float minDistance = 1.0f; - private float maxDistance = 40.0f; - - private float distance = 20; - - private float rotationSpeed = 1.0f; - private float rotation = 0; - - private float trailingRotationInertia = 0.05f; - - private float zoomSensitivity = 2f; - private float rotationSensitivity = 5f; - private float chasingSensitivity = 5f; - private float trailingSensitivity = 0.5f; - - private float verticalRotation = FastMath.PI / 6; - - private float rotationLerpFactor = 0; - private float trailingLerpFactor = 0; - - /** - * Целевой разворот камеры. - */ - private float targetRotation = rotation; - - /** - * Целевой разворот камеры по вертикали. - */ - private float targetVRotation = verticalRotation; - - private float vRotationLerpFactor = 0; - private float targetDistance = distance; - private float distanceLerpFactor = 0; - - private float offsetDistance = 0.002f; - - private float previousTargetRotation; - - private boolean enabled = true; - private boolean dragToRotate = true; - private boolean trailingEnabled = true; - private boolean hideCursorOnRotate = true; - - private boolean rotating = false; - private boolean verticalRotating = false; - private boolean smoothMotion = false; - private boolean targetMoves = false; - - private boolean zooming = false; - private boolean trailing = false; - private boolean chasing = false; - private boolean canRotate; - private boolean zoomin; - private boolean lockRotation; - - /** - * Constructs the chase camera - * - * @param camera the application camera - * @param target the spatial to follow - */ - public EditorCamera(@NotNull final Camera camera, @NotNull final Spatial target) { - this(camera); - target.addControl(this); - } - - /** - * Constructs the chase camera if you use this constructor you have to attach the camera later to a spatial doing - * spatial.addControl(chaseCamera); - * - * @param camera the application camera - */ - public EditorCamera(@NotNull final Camera camera) { - this.camera = camera; - this.initialUpVec = Vector3f.UNIT_Y; - this.targetDir = new Vector3f(); - this.position = new Vector3f(); - this.targetLocation = new Vector3f(0, 0, 0); - this.lookAtOffset = new Vector3f(0, 0, 0); - this.temp = new Vector3f(0, 0, 0); - } - - /** - * Разворот камеры. - * - * @param direction the direction - * @param value the value - */ - public void rotateTo(final Direction direction, final float value) { - - float targetRotation = radiansToDegree(getTargetRotation()); - float targetVRotation = radiansToDegree(getTargetVRotation()); - - if (direction == Direction.LEFT) { - targetRotation += value; - } else if (direction == Direction.RIGHT) { - targetRotation -= value; - } else if (direction == Direction.TOP) { - targetVRotation += value; - } else if (direction == Direction.BOTTOM) { - targetVRotation -= value; - } - - setTargetRotation(degreeToRadians(targetRotation)); - setTargetVRotation(degreeToRadians(targetVRotation)); - } - - /** - * Разворот камеры. - * - * @param perspective the perspective - */ - public void rotateTo(final Perspective perspective) { - - float targetRotation = degreeToRadians(90); - float targetVRotation = degreeToRadians(0); - - if (perspective == Perspective.BACK) { - targetRotation = degreeToRadians(-90); - } else if (perspective == Perspective.RIGHT) { - targetRotation = degreeToRadians(180); - } else if (perspective == Perspective.BOTTOM) { - targetVRotation = degreeToRadians(90); - } else if (perspective == Perspective.TOP) { - targetVRotation = degreeToRadians(-90); - } - - setTargetRotation(targetRotation); - setTargetVRotation(targetVRotation); - } - - /** - * @return целевой разворот камеры. - */ - private float getTargetRotation() { - return targetRotation; - } - - /** - * Sets target rotation. - * - * @param targetRotation целевой разворот камеры. - */ - public void setTargetRotation(final float targetRotation) { - this.targetRotation = targetRotation; - } - - /** - * @return целевой разворот камеры по вертикали. - */ - private float getTargetVRotation() { - return targetVRotation; - } - - /** - * Sets target v rotation. - * - * @param targetVRotation целевой разворот камеры по вертикали. - */ - public void setTargetVRotation(final float targetVRotation) { - this.targetVRotation = targetVRotation; - } - - @Override - public void onAction(final String name, final boolean keyPressed, final float tpf) { - - if (!enabled || !dragToRotate) { - return; - } else if (!name.equals(CHASECAM_TOGGLEROTATE)) { - return; - } - - if (Config.DEV_CAMERA_DEBUG) { - LOGGER.debug(this, keyPressed, flag -> "Toggle camera " + flag); - } - - if (keyPressed) { - canRotate = true; - if (hideCursorOnRotate) inputManager.setCursorVisible(false); - } else { - canRotate = false; - if (hideCursorOnRotate) inputManager.setCursorVisible(true); - } - } - - /** - * Sets lock rotation. - * - * @param lockRotation the lock rotation - */ - public void setLockRotation(boolean lockRotation) { - this.lockRotation = lockRotation; - } - - @Override - public void onAnalog(String name, float value, float tpf) { - if (!enabled) return; - - if (name.equals(CHASECAM_MOVELEFT) && !lockRotation) { - rotateCamera(-value * 3); - } else if (name.equals(CHASECAM_MOVERIGHT) && !lockRotation) { - rotateCamera(value * 3); - } else if (name.equals(CHASECAM_UP) && !lockRotation) { - verticalRotateCamera(value * 3); - } else if (name.equals(CHASECAM_DOWN) && !lockRotation) { - verticalRotateCamera(-value * 3); - } else if (name.equals(CHASECAM_ZOOMIN)) { - zoomCamera(-value); - if (!zoomin) distanceLerpFactor = 0; - zoomin = true; - } else if (name.equals(CHASECAM_ZOOMOUT)) { - zoomCamera(value); - if (zoomin) distanceLerpFactor = 0; - zoomin = false; - } - } - - /** - * Registers inputs with the input manager - * - * @param inputManager the input manager - */ - public final void registerInput(final InputManager inputManager) { - this.inputManager = inputManager; - - if (!inputManager.hasMapping(CHASECAM_DOWN)) { - inputManager.addMapping(CHASECAM_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); - } - - if (!inputManager.hasMapping(CHASECAM_UP)) { - inputManager.addMapping(CHASECAM_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); - } - - if (!inputManager.hasMapping(CHASECAM_ZOOMIN)) { - inputManager.addMapping(CHASECAM_ZOOMIN, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); - } - - if (!inputManager.hasMapping(CHASECAM_ZOOMOUT)) { - inputManager.addMapping(CHASECAM_ZOOMOUT, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); - } - - if (!inputManager.hasMapping(CHASECAM_MOVELEFT)) { - inputManager.addMapping(CHASECAM_MOVELEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true)); - } - - if (!inputManager.hasMapping(CHASECAM_MOVERIGHT)) { - inputManager.addMapping(CHASECAM_MOVERIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false)); - } - - if (!inputManager.hasMapping(CHASECAM_TOGGLEROTATE)) { - inputManager.addMapping(CHASECAM_TOGGLEROTATE, new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); - } - - inputManager.addListener(this, ALL_INPUTS); - } - - /** - * Unregister input. - * - * @param inputManager the input manager - */ - public void unregisterInput(final InputManager inputManager) { - inputManager.removeListener(this); - } - - /** - * Compute position. - */ - protected void computePosition() { - - float highDistance = (distance) * FastMath.sin((FastMath.PI / 2) - verticalRotation); - - position.set(highDistance * FastMath.cos(rotation), (distance) * FastMath.sin(verticalRotation), highDistance * FastMath.sin(rotation)); - position.addLocal(target.getWorldTranslation()); - } - - /** - * Rotate camera. - * - * @param value the value - */ - //rotate the camera around the target on the horizontal plane - protected void rotateCamera(float value) { - if (!canRotate || !enabled) return; - rotating = true; - targetRotation += value * rotationSpeed; - } - - /** - * Gets target distance. - * - * @return the target distance - */ - public float getTargetDistance() { - return targetDistance; - } - - /** - * Sets target distance. - * - * @param targetDistance the target distance - */ - public void setTargetDistance(final float targetDistance) { - this.targetDistance = max(min(targetDistance, maxDistance), minDistance); - } - - /** - * Zoom camera. - * - * @param value the value - */ - //move the camera toward or away the target - protected void zoomCamera(float value) { - if (!enabled) return; - - zooming = true; - targetDistance += value * zoomSensitivity * sqrt(targetDistance); - targetDistance = max(min(targetDistance, maxDistance), minDistance); - } - - /** - * Vertical rotate camera. - * - * @param value the value - */ - //rotate the camera around the target on the vertical plane - protected void verticalRotateCamera(final float value) { - if (!canRotate || !enabled) return; - - verticalRotating = true; - targetVRotation += value * rotationSpeed; - } - - /** - * Updates the camera, should only be called internally - * - * @param tpf the tpf - */ - public void updateCamera(float tpf) { - - if (!enabled) { - return; - } - - targetLocation.set(target.getWorldTranslation()) - .addLocal(lookAtOffset); - - if (smoothMotion) { - - //computation of target direction - targetDir.set(targetLocation).subtractLocal(prevPos); - float dist = targetDir.length(); - - //Low pass filtering on the target postition to avoid shaking when physics are enabled. - if (offsetDistance < dist) { - //target moves, start chasing. - chasing = true; - //target moves, start trailing if it has to. - if (trailingEnabled) { - trailing = true; - } - //target moves... - targetMoves = true; - } else { - //if target was moving, we compute a slight offset in rotation to avoid a rought stop of the camera - //We do not if the player is rotationg the camera - if (targetMoves && !canRotate) { - if (targetRotation - rotation > trailingRotationInertia) { - targetRotation = rotation + trailingRotationInertia; - } else if (targetRotation - rotation < -trailingRotationInertia) { - targetRotation = rotation - trailingRotationInertia; - } - } - //Target stops - targetMoves = false; - } - - //the user is rotating the camera by dragging the mouse - if (canRotate) { - //reseting the trailing lerp factor - trailingLerpFactor = 0; - //stop trailing user has the control - trailing = false; - } - - - if (trailingEnabled && trailing) { - if (targetMoves) { - //computation if the inverted direction of the target - Vector3f a = targetDir.negate().normalizeLocal(); - //the x unit vector - Vector3f b = Vector3f.UNIT_X; - //2d is good enough - a.y = 0; - //computation of the rotation angle between the x axis and the trail - if (targetDir.z > 0) { - targetRotation = FastMath.TWO_PI - FastMath.acos(a.dot(b)); - } else { - targetRotation = FastMath.acos(a.dot(b)); - } - if (targetRotation - rotation > FastMath.PI || targetRotation - rotation < -FastMath.PI) { - targetRotation -= FastMath.TWO_PI; - } - - //if there is an important change in the direction while trailing reset of the lerp factor to avoid jumpy movements - if (targetRotation != previousTargetRotation && FastMath.abs(targetRotation - previousTargetRotation) > FastMath.PI / 8) { - trailingLerpFactor = 0; - } - previousTargetRotation = targetRotation; - } - //computing lerp factor - trailingLerpFactor = min(trailingLerpFactor + tpf * tpf * trailingSensitivity, 1); - //computing rotation by linear interpolation - rotation = FastMath.interpolateLinear(trailingLerpFactor, rotation, targetRotation); - - //if the rotation is near the target rotation we're good, that's over - if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) { - trailing = false; - trailingLerpFactor = 0; - } - } - - //linear interpolation of the distance while chasing - if (chasing) { - distance = temp.set(targetLocation).subtractLocal(camera.getLocation()).length(); - distanceLerpFactor = min(distanceLerpFactor + (tpf * tpf * chasingSensitivity * 0.05f), 1); - distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance); - if (targetDistance + 0.01f >= distance && targetDistance - 0.01f <= distance) { - distanceLerpFactor = 0; - chasing = false; - } - } - - //linear interpolation of the distance while zooming - if (zooming) { - distanceLerpFactor = min(distanceLerpFactor + (tpf * tpf * zoomSensitivity), 1); - distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance); - if (targetDistance + 0.1f >= distance && targetDistance - 0.1f <= distance) { - zooming = false; - distanceLerpFactor = 0; - } - } - - //linear interpolation of the rotation while rotating horizontally - if (rotating) { - rotationLerpFactor = min(rotationLerpFactor + tpf * tpf * rotationSensitivity, 1); - rotation = FastMath.interpolateLinear(rotationLerpFactor, rotation, targetRotation); - if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) { - rotating = false; - rotationLerpFactor = 0; - } - } - - //linear interpolation of the rotation while rotating vertically - if (verticalRotating) { - vRotationLerpFactor = min(vRotationLerpFactor + tpf * tpf * rotationSensitivity, 1); - verticalRotation = FastMath.interpolateLinear(vRotationLerpFactor, verticalRotation, targetVRotation); - if (targetVRotation + 0.01f >= verticalRotation && targetVRotation - 0.01f <= verticalRotation) { - verticalRotating = false; - vRotationLerpFactor = 0; - } - } - //computing the position - computePosition(); - //setting the position at last - camera.setLocation(position.addLocal(lookAtOffset)); - } else { - //easy no smooth motion - verticalRotation = targetVRotation; - rotation = targetRotation; - distance = targetDistance; - computePosition(); - camera.setLocation(position.addLocal(lookAtOffset)); - } - //keeping track on the previous position of the target - prevPos.set(targetLocation); - - //the camera looks at the target - camera.lookAt(targetLocation, initialUpVec); - } - - /** - * Return the enabled/disabled state of the camera - * - * @return true if the camera is enabled - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Enable or disable the camera - * - * @param enabled true to enable - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (!enabled) { - canRotate = false; // reset this flag in-case it was on before - } - } - - /** - * Returns the max zoom distance of the camera (default is 40) - * - * @return maxDistance max distance - */ - public float getMaxDistance() { - return maxDistance; - } - - /** - * Sets the max zoom distance of the camera (default is 40) - * - * @param maxDistance the max distance - */ - public void setMaxDistance(float maxDistance) { - this.maxDistance = maxDistance; - if (maxDistance < distance) { - zoomCamera(maxDistance - distance); - } - } - - /** - * Returns the min zoom distance of the camera (default is 1) - * - * @return minDistance min distance - */ - public float getMinDistance() { - return minDistance; - } - - /** - * Sets the min zoom distance of the camera (default is 1) - * - * @param minDistance the min distance - */ - public void setMinDistance(float minDistance) { - this.minDistance = minDistance; - if (minDistance > distance) { - zoomCamera(distance - minDistance); - } - } - - /** - * clone this camera for a spatial - */ - @Override - public Control cloneForSpatial(Spatial spatial) { - - final EditorCamera editorCamera = new EditorCamera(camera, spatial); - editorCamera.setMaxDistance(getMaxDistance()); - editorCamera.setMinDistance(getMinDistance()); - - if (inputManager != null) { - editorCamera.registerInput(inputManager); - } - - return editorCamera; - } - - /** - * Sets the spacial for the camera control, should only be used internally - */ - public void setSpatial(Spatial spatial) { - target = spatial; - - if (spatial == null) return; - - computePosition(); - - prevPos = new Vector3f(target.getWorldTranslation()); - camera.setLocation(position); - } - - /** - * update the camera control, should only be used internally - */ - public void update(float tpf) { - } - - /** - * renders the camera control, should only be used internally - */ - public void render(RenderManager rm, ViewPort vp) { - //nothing to render - } - - /** - * Write the camera - * - * @param ex the exporter - */ - public void write(JmeExporter ex) throws IOException { - throw new UnsupportedOperationException("remove ChaseCamera before saving"); - } - - /** - * Read the camera - */ - public void read(JmeImporter im) throws IOException { - InputCapsule ic = im.getCapsule(this); - maxDistance = ic.readFloat("maxDistance", 40); - minDistance = ic.readFloat("minDistance", 1); - } - - /** - * Is smooth motion boolean. - * - * @return True is smooth motion is enabled for this chase camera - */ - public boolean isSmoothMotion() { - return smoothMotion; - } - - /** - * Enables smooth motion for this chase camera - * - * @param smoothMotion the smooth motion - */ - public void setSmoothMotion(boolean smoothMotion) { - this.smoothMotion = smoothMotion; - } - - /** - * returns the chasing sensitivity - * - * @return the chasing sensitivity - */ - public float getChasingSensitivity() { - return chasingSensitivity; - } - - /** - * Sets the chasing sensitivity, the lower the value the slower the camera will follow the target when it moves - * default is 5 Only has an effect if smoothMotion is set to true and trailing is enabled - * - * @param chasingSensitivity the chasing sensitivity - */ - public void setChasingSensitivity(float chasingSensitivity) { - this.chasingSensitivity = chasingSensitivity; - } - - /** - * Returns the rotation sensitivity - * - * @return the rotation sensitivity - */ - public float getRotationSensitivity() { - return rotationSensitivity; - } - - /** - * Sets the rotation sensitivity, the lower the value the slower the camera will rotates around the target when - * draging with the mouse default is 5, values over 5 should have no effect. If you want a significant slow down try - * values below 1. Only has an effect if smoothMotion is set to true - * - * @param rotationSensitivity the rotation sensitivity - */ - public void setRotationSensitivity(float rotationSensitivity) { - this.rotationSensitivity = rotationSensitivity; - } - - /** - * returns true if the trailing is enabled - * - * @return the boolean - */ - public boolean isTrailingEnabled() { - return trailingEnabled; - } - - /** - * Enable the camera trailing : The camera smoothly go in the targets trail when it moves. Only has an effect if - * smoothMotion is set to true - * - * @param trailingEnabled the trailing enabled - */ - public void setTrailingEnabled(boolean trailingEnabled) { - this.trailingEnabled = trailingEnabled; - } - - /** - * returns the trailing rotation inertia - * - * @return the trailing rotation inertia - */ - public float getTrailingRotationInertia() { - return trailingRotationInertia; - } - - /** - * Sets the trailing rotation inertia : default is 0.1. This prevent the camera to roughtly stop when the target - * stops moving before the camera reached the trail position. Only has an effect if smoothMotion is set to true and - * trailing is enabled - * - * @param trailingRotationInertia the trailing rotation inertia - */ - public void setTrailingRotationInertia(float trailingRotationInertia) { - this.trailingRotationInertia = trailingRotationInertia; - } - - /** - * returns the trailing sensitivity - * - * @return the trailing sensitivity - */ - public float getTrailingSensitivity() { - return trailingSensitivity; - } - - /** - * Only has an effect if smoothMotion is set to true and trailing is enabled Sets the trailing sensitivity, the - * lower the value, the slower the camera will go in the target trail when it moves. default is 0.5; - * - * @param trailingSensitivity the trailing sensitivity - */ - public void setTrailingSensitivity(float trailingSensitivity) { - this.trailingSensitivity = trailingSensitivity; - } - - /** - * returns the zoom sensitivity - * - * @return the zoom sensitivity - */ - public float getZoomSensitivity() { - return zoomSensitivity; - } - - /** - * Sets the zoom sensitivity, the lower the value, the slower the camera will zoom in and out. default is 2. - * - * @param zoomSensitivity the zoom sensitivity - */ - public void setZoomSensitivity(float zoomSensitivity) { - this.zoomSensitivity = zoomSensitivity; - } - - /** - * Returns the rotation speed when the mouse is moved. - * - * @return the rotation speed when the mouse is moved. - */ - public float getRotationSpeed() { - return rotationSpeed; - } - - /** - * Sets the rotate amount when user moves his mouse, the lower the value, the slower the camera will rotate. - * default is 1. - * - * @param rotationSpeed Rotation speed on mouse movement, default is 1. - */ - public void setRotationSpeed(float rotationSpeed) { - this.rotationSpeed = rotationSpeed; - } - - /** - * Sets the default distance at start of applicaiton - * - * @param defaultDistance the default distance - */ - public void setDefaultDistance(float defaultDistance) { - distance = defaultDistance; - targetDistance = distance; - } - - /** - * sets the default horizontal rotation in radian of the camera at start of the application - * - * @param angleInRad the angle in rad - */ - public void setDefaultHorizontalRotation(float angleInRad) { - rotation = angleInRad; - targetRotation = angleInRad; - } - - /** - * sets the default vertical rotation in radian of the camera at start of the application - * - * @param angleInRad the angle in rad - */ - public void setDefaultVerticalRotation(float angleInRad) { - verticalRotation = angleInRad; - targetVRotation = angleInRad; - } - - /** - * Is drag to rotate boolean. - * - * @return If drag to rotate feature is enabled. - * @see FlyByCamera#setDragToRotate(boolean) FlyByCamera#setDragToRotate(boolean)FlyByCamera#setDragToRotate(boolean) - */ - public boolean isDragToRotate() { - return dragToRotate; - } - - /** - * Sets drag to rotate. - * - * @param dragToRotate When true, the user must hold the mouse button and drag over the screen to rotate the camera, and the cursor is visible until dragged. Otherwise, the cursor is invisible at all times and holding the mouse button is not needed to rotate the camera. This feature is disabled by default. - */ - public void setDragToRotate(boolean dragToRotate) { - this.dragToRotate = dragToRotate; - this.canRotate = !dragToRotate; - - if (inputManager != null) { - inputManager.setCursorVisible(dragToRotate); - } - } - - /** - * return the current distance from the camera to the target - * - * @return the distance to target - */ - public float getDistanceToTarget() { - return distance; - } - - /** - * returns the current horizontal rotation around the target in radians - * - * @return the horizontal rotation - */ - public float getHorizontalRotation() { - return rotation; - } - - /** - * returns the current vertical rotation around the target in radians. - * - * @return the vertical rotation - */ - public float getVerticalRotation() { - return verticalRotation; - } - - /** - * returns the offset from the target's position where the camera looks at - * - * @return the look at offset - */ - public Vector3f getLookAtOffset() { - return lookAtOffset; - } - - /** - * Sets the offset from the target's position where the camera looks at - * - * @param lookAtOffset the look at offset - */ - public void setLookAtOffset(Vector3f lookAtOffset) { - this.lookAtOffset = lookAtOffset; - } - - /** - * Sets the up vector of the camera used for the lookAt on the target - * - * @param up the up - */ - public void setUpVector(Vector3f up) { - initialUpVec = up; - } - - /** - * Returns the up vector of the camera used for the lookAt on the target - * - * @return the up vector - */ - public Vector3f getUpVector() { - return initialUpVec; - } - - /** - * Is hide cursor on rotate boolean. - * - * @return the boolean - */ - public boolean isHideCursorOnRotate() { - return hideCursorOnRotate; - } - - /** - * Sets hide cursor on rotate. - * - * @param hideCursorOnRotate the hide cursor on rotate - */ - public void setHideCursorOnRotate(boolean hideCursorOnRotate) { - this.hideCursorOnRotate = hideCursorOnRotate; - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/model/scene/EditorPresentableNode.java b/src/main/java/com/ss/editor/model/scene/EditorPresentableNode.java deleted file mode 100644 index 0c0907b6..00000000 --- a/src/main/java/com/ss/editor/model/scene/EditorPresentableNode.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.ss.editor.model.scene; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.extension.scene.ScenePresentable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The node to present and edit objects on a scene which aren't models. - * - * @author JavaSaBr - */ -public class EditorPresentableNode extends Node { - - private class EditedNode extends Node implements VisibleOnlyWhenSelected, NoSelection, WrapperNode { - - private EditedNode(@NotNull final String name) { - super(name); - } - - - @Override - @FromAnyThread - public @NotNull Object getWrappedObject() { - return notNull(getObject()); - } - - @Override - @JmeThread - public void setCullHint(final CullHint hint) { - super.setCullHint(hint); - notNull(getModel()).setCullHint(hint); - } - } - - /** - * The presented object. - */ - @Nullable - private ScenePresentable object; - - /** - * The node to edit. - */ - @NotNull - private final EditedNode editedNode; - - /** - * The view model. - */ - @Nullable - private Geometry model; - - public EditorPresentableNode() { - this.editedNode = new EditedNode("EditedNode"); - attachChild(editedNode); - } - - /** - * Set the object. - * - * @param object the object. - */ - @JmeThread - public void setObject(@Nullable final ScenePresentable object) { - this.object = object; - } - - /** - * Get the edited node. - * - * @return the edited node. - */ - @JmeThread - public @NotNull Node getEditedNode() { - return editedNode; - } - - /** - * Get the object. - * - * @return the object. - */ - @JmeThread - public @Nullable ScenePresentable getObject() { - return object; - } - - /** - * Get the model. - * - * @return the model. - */ - @JmeThread - public @Nullable Geometry getModel() { - return model; - } - - /** - * Set the model. - * - * @param model the model. - */ - @JmeThread - public void setModel(@Nullable final Geometry model) { - this.model = model; - } - - @Override - @JmeThread - public void updateGeometricState() { - - final ScenePresentable object = getObject(); - - if (object != null) { - final Node editedNode = getEditedNode(); - object.setRotation(editedNode.getLocalRotation()); - object.setLocation(editedNode.getLocalTranslation()); - object.setScale(editedNode.getLocalScale()); - } - - super.updateGeometricState(); - } - - /** - * Synchronize this node with presented object. - */ - @JmeThread - public void sync() { - - final ScenePresentable object = getObject(); - - final Node editedNode = getEditedNode(); - editedNode.setLocalRotation(object.getRotation()); - editedNode.setLocalTranslation(object.getLocation()); - editedNode.setLocalScale(object.getScale()); - } - - /** - * Update position and rotation of a model. - */ - @JmeThread - public void updateModel() { - - final ScenePresentable object = getObject(); - final Geometry model = getModel(); - if (model == null || object == null) return; - - // TODO implement getting parent - /*final Node parent = object.getParent(); - - if (parent != null) { - setLocalTranslation(parent.getWorldTranslation()); - setLocalRotation(parent.getWorldRotation()); - setLocalScale(parent.getWorldScale()); - }*/ - - final Node editedNode = getEditedNode(); - model.setLocalTranslation(editedNode.getWorldTranslation()); - model.setLocalRotation(editedNode.getWorldRotation()); - model.setLocalScale(editedNode.getWorldScale()); - } -} diff --git a/src/main/java/com/ss/editor/model/scene/WrapperNode.java b/src/main/java/com/ss/editor/model/scene/WrapperNode.java deleted file mode 100644 index 6e59dea9..00000000 --- a/src/main/java/com/ss/editor/model/scene/WrapperNode.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.ss.editor.model.scene; - -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The interface to mark some object about that the object has another object to update. - * - * @author JavaSaBr - */ -public interface WrapperNode { - - @FromAnyThread - @NotNull Object getWrappedObject(); -} diff --git a/src/main/java/com/ss/editor/model/undo/EditorOperation.java b/src/main/java/com/ss/editor/model/undo/EditorOperation.java deleted file mode 100644 index a7bb44f3..00000000 --- a/src/main/java/com/ss/editor/model/undo/EditorOperation.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.ss.editor.model.undo; - -import com.ss.editor.annotation.FxThread; - -import org.jetbrains.annotations.NotNull; - -/** - * The interface for implementing an operation in an editor. - * - * @author JavaSabr - */ -public interface EditorOperation { - - /** - * Redo this operation for the editor. - * - * @param editor the editor. - */ - @FxThread - default void redo(@NotNull final UndoableEditor editor) { - } - - /** - * Undo this operation for the editor. - * - * @param editor the editor. - */ - @FxThread - default void undo(@NotNull final UndoableEditor editor) { - } -} diff --git a/src/main/java/com/ss/editor/model/undo/UndoableEditor.java b/src/main/java/com/ss/editor/model/undo/UndoableEditor.java deleted file mode 100644 index 20f829cc..00000000 --- a/src/main/java/com/ss/editor/model/undo/UndoableEditor.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.model.undo; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; - -/** - * The interface to implement an undoable editor. - * - * @author JavaSaBr - */ -public interface UndoableEditor { - - /** - * Increment changes count. - */ - @FxThread - void incrementChange(); - - /** - * Decrement changes count. - */ - @FxThread - void decrementChange(); - - /** - * Redo the last operation. - */ - @FromAnyThread - void redo(); - - /** - * Undo the last operation. - */ - @FromAnyThread - void undo(); -} diff --git a/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java b/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java deleted file mode 100644 index 9837911a..00000000 --- a/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.ss.editor.model.undo.editor; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.EditorOperation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The interface to notify about any changes. - * - * @author JavaSaBr - */ -public interface ChangeConsumer { - - /** - * Notify about an attempt to change the property from jME thread. - * - * @param object the object. - * @param propertyName the property name. - */ - @JmeThread - default void notifyJmePreChangeProperty(@NotNull Object object, @NotNull String propertyName) { - } - - /** - * Notify about changed the property from jME thread. - * - * @param object the object. - * @param propertyName the property name. - */ - @JmeThread - default void notifyJmeChangedProperty(@NotNull Object object, @NotNull String propertyName) { - } - - /** - * Notify about changed property from jME thread. - * - * @param object the object - * @param propertyName the property name - */ - @FxThread - default void notifyFxChangeProperty(@NotNull Object object, @NotNull String propertyName) { - notifyFxChangeProperty(null, object, propertyName); - } - - /** - * Notify about changed property count in the object from FX thread. - * - * @param object the object - */ - @FxThread - default void notifyFxChangePropertyCount(@NotNull Object object) { - } - - /** - * Notify about changed property. - * - * @param parent the parent - * @param object the object - * @param propertyName the property name - */ - @FxThread - default void notifyFxChangeProperty(@Nullable Object parent, @NotNull Object object, @NotNull String propertyName) { - } - - /** - * Notify about added child from FX thread. - * - * @param parent the parent. - * @param added the added. - * @param index the index of position. - * @param needSelect true if need to select the child. - */ - @FxThread - default void notifyFxAddedChild(@NotNull Object parent, @NotNull Object added, int index, boolean needSelect) { - } - - /** - * Notify about removed child from FX thread. - * - * @param parent the parent - * @param removed the removed - */ - @FxThread - default void notifyFxRemovedChild(@NotNull Object parent, @NotNull Object removed) { - } - - /** - * Notify about replaced child from FX thread. - * - * @param parent the parent. - * @param oldChild the old child. - * @param newChild the new child. - * @param needExpand true of need to expand new node. - * @param needDeepExpand true of need to expand new node deeply. - */ - @FxThread - default void notifyFxReplaced(@NotNull Object parent, @Nullable Object oldChild, @Nullable Object newChild, - boolean needExpand, boolean needDeepExpand) { - } - - /** - * Notify about moved child from FX thread. - * - * @param prevParent the prev parent. - * @param newParent the new parent. - * @param child the child. - * @param index the index of position. - * @param needSelect true if need select this object. - */ - @FxThread - default void notifyFxMoved(@NotNull Object prevParent, @NotNull Object newParent, @NotNull Object child, int index, - boolean needSelect) { - } - - /** - * Execute the operation. - * - * @param operation the operation - */ - @FromAnyThread - void execute(@NotNull EditorOperation operation); -} diff --git a/src/main/java/com/ss/editor/model/undo/editor/ModelChangeConsumer.java b/src/main/java/com/ss/editor/model/undo/editor/ModelChangeConsumer.java deleted file mode 100644 index b583eb5a..00000000 --- a/src/main/java/com/ss/editor/model/undo/editor/ModelChangeConsumer.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.ss.editor.model.undo.editor; - -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; -import org.jetbrains.annotations.NotNull; - -/** - * The interface to notify about any changes of models. - * - * @author JavaSaBr - */ -public interface ModelChangeConsumer extends ChangeConsumer { - - /** - * Get the current model. - * - * @return the current model of the editor. - */ - @FxThread - @NotNull Spatial getCurrentModel(); -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AbstractEditorOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AbstractEditorOperation.java deleted file mode 100644 index 26c71d60..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AbstractEditorOperation.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.EditorOperation; -import com.ss.editor.model.undo.UndoableEditor; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import org.jetbrains.annotations.NotNull; - -/** - * The base implementation of the {@link EditorOperation} to support a generic type of an editor. - * - * @param the change consumer's type. - * @author JavaSabr - */ -public abstract class AbstractEditorOperation implements EditorOperation { - - /** - * The logger. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(EditorOperation.class); - - /** - * The executor manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - public AbstractEditorOperation() { - } - - @Override - @FxThread - public void redo(@NotNull final UndoableEditor editor) { - redoImpl(unsafeCast(editor)); - } - - /** - * Execute changes. - * - * @param editor the editor. - */ - @FxThread - protected abstract void redoImpl(@NotNull E editor); - - @Override - @FxThread - public void undo(@NotNull final UndoableEditor editor) { - undoImpl(unsafeCast(editor)); - } - - /** - * Revert changes. - * - * @param editor the editor. - */ - @FxThread - protected abstract void undoImpl(@NotNull final E editor); -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddAppStateOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddAppStateOperation.java deleted file mode 100644 index fdb3922c..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddAppStateOperation.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a new {@link SceneAppState} to a {@link SceneNode}. - * - * @author JavaSaBr. - */ -public class AddAppStateOperation extends AbstractEditorOperation { - - /** - * The new scene app state. - */ - @NotNull - private final SceneAppState newState; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - public AddAppStateOperation(@NotNull final SceneAppState newState, @NotNull final SceneNode sceneNode) { - this.newState = newState; - this.sceneNode = sceneNode; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addAppState(newState); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyAddedAppState(newState)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.removeAppState(newState); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyRemovedAppState(newState)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java deleted file mode 100644 index da9c9d31..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.plugin.api.RenderFilterExtension; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a new {@link Spatial} to a {@link Node}. - * - * @author JavaSaBr - */ -public class AddChildOperation extends AbstractEditorOperation { - - /** - * The new child. - */ - @NotNull - private final Spatial newChild; - - /** - * The parent. - */ - @NotNull - private final Node parent; - - /** - * The flag to select added child. - */ - private final boolean needSelect; - - public AddChildOperation(@NotNull final Spatial newChild, @NotNull final Node parent) { - this(newChild, parent, true); - } - - public AddChildOperation(@NotNull final Spatial newChild, @NotNull final Node parent, boolean needSelect) { - this.newChild = newChild; - this.parent = parent; - this.needSelect = needSelect; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - editor.notifyJmePreChangeProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); - parent.attachChildAt(newChild, 0); - editor.notifyJmeChangedProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.refreshFilters(); - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(parent, newChild, 0, needSelect)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.detachChild(newChild); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(parent, newChild)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java deleted file mode 100644 index cea63f40..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a control to a node. - * - * @author JavaSaBr - */ -public class AddControlOperation extends AbstractEditorOperation { - - /** - * The new control. - */ - @NotNull - private final Control newControl; - - /** - * The parent. - */ - @NotNull - private final Spatial spatial; - - /** - * Instantiates a new Add control operation. - * - * @param newControl the new control - * @param spatial the spatial - */ - public AddControlOperation(@NotNull final Control newControl, @NotNull final Spatial spatial) { - this.newControl = newControl; - this.spatial = spatial; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - spatial.addControl(newControl); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(spatial, newControl, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - spatial.removeControl(newControl); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(spatial, newControl)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java deleted file mode 100644 index 89227b7e..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.light.Light; -import com.jme3.scene.Node; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a {@link Light} to a {@link Node}. - * - * @author JavaSaBr - */ -public class AddLightOperation extends AbstractEditorOperation { - - /** - * The new light. - */ - @NotNull - private final Light light; - - /** - * The parent. - */ - @NotNull - private final Node parent; - - /** - * Instantiates a new Add light operation. - * - * @param light the light - * @param parent the parent - */ - public AddLightOperation(@NotNull final Light light, @NotNull Node parent) { - this.light = light; - this.parent = parent; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.addLight(light); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(parent, light, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.removeLight(light); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(parent, light)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddSceneFilterOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddSceneFilterOperation.java deleted file mode 100644 index a5477e9c..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddSceneFilterOperation.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a new {@link SceneFilter} to a {@link SceneNode}. - * - * @author JavaSaBr. - */ -public class AddSceneFilterOperation extends AbstractEditorOperation { - - /** - * The new filter. - */ - @NotNull - private final SceneFilter sceneFilter; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - public AddSceneFilterOperation(@NotNull final SceneFilter sceneFilter, @NotNull final SceneNode sceneNode) { - this.sceneFilter = sceneFilter; - this.sceneNode = sceneNode; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addFilter(sceneFilter); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyAddedFilter(sceneFilter)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.removeFilter(sceneFilter); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyRemovedFilter(sceneFilter)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java deleted file mode 100644 index 8a0ba5b7..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.bullet.objects.VehicleWheel; -import com.jme3.math.Vector3f; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The operation to add a wheel to a vehicle control. - * - * @author JavaSaBr - */ -public class AddVehicleWheelOperation extends AbstractEditorOperation { - - /** - * The vehicle control. - */ - @NotNull - private final VehicleControl control; - - /** - * The connection point. - */ - @NotNull - private final Vector3f connectionPoint; - - /** - * The direction. - */ - @NotNull - private final Vector3f direction; - - /** - * The axle. - */ - @NotNull - private final Vector3f axle; - - /** - * The wheel. - */ - @Nullable - private VehicleWheel createdWheel; - - /** - * The rest length. - */ - private final float restLength; - - /** - * The wheel radius. - */ - private final float wheelRadius; - - /** - * The flag is front wheel. - */ - private final boolean isFrontWheel; - - /** - * Instantiates a new Add vehicle wheel operation. - * - * @param control the control - * @param connectionPoint the connection point - * @param direction the direction - * @param axle the axle - * @param restLength the rest length - * @param wheelRadius the wheel radius - * @param isFrontWheel the is front wheel - */ - public AddVehicleWheelOperation(@NotNull final VehicleControl control, @NotNull final Vector3f connectionPoint, - @NotNull final Vector3f direction, @NotNull final Vector3f axle, - final float restLength, final float wheelRadius, final boolean isFrontWheel) { - this.control = control; - this.connectionPoint = connectionPoint; - this.direction = direction; - this.axle = axle; - this.restLength = restLength; - this.wheelRadius = wheelRadius; - this.isFrontWheel = isFrontWheel; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final VehicleWheel vehicleWheel = control.addWheel(connectionPoint, direction, axle, restLength, - wheelRadius, isFrontWheel); - - this.createdWheel = vehicleWheel; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(control, vehicleWheel, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (int i = 0, length = control.getNumWheels(); i < length; i++) { - final VehicleWheel wheel = control.getWheel(i); - if (wheel == createdWheel) { - control.removeWheel(i); - break; - } - } - - final VehicleWheel toRemove = notNull(createdWheel); - - this.createdWheel = null; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(control, toRemove)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java deleted file mode 100644 index ca72e05e..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.bullet.collision.PhysicsCollisionObject; -import com.jme3.bullet.collision.shapes.CollisionShape; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The operation to change a collision shape of a model. - * - * @author JavaSaBr - */ -public class ChangeCollisionShapeOperation extends AbstractEditorOperation { - - /** - * The new shape. - */ - @NotNull - private final CollisionShape newShape; - - /** - * The previous shape. - */ - @NotNull - private final CollisionShape oldShape; - - /** - * The collision object. - */ - @NotNull - private final PhysicsCollisionObject collisionObject; - - /** - * Instantiates a new Change collision shape operation. - * - * @param newShape the new shape - * @param oldShape the old shape - * @param collisionObject the collision object - */ - public ChangeCollisionShapeOperation(@NotNull final CollisionShape newShape, @NotNull final CollisionShape oldShape, - @NotNull final PhysicsCollisionObject collisionObject) { - this.newShape = newShape; - this.oldShape = oldShape; - this.collisionObject = collisionObject; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(collisionObject, oldShape)); - collisionObject.setCollisionShape(newShape); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(collisionObject, newShape, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(collisionObject, newShape)); - collisionObject.setCollisionShape(oldShape); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(collisionObject, oldShape, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java deleted file mode 100644 index 8ed9c8a7..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of {@link AbstractEditorOperation} to chane {@link com.jme3.scene.control.AbstractControl} in {@link Node}. - * - * @author JavaSaBr. - */ -public class ChangeControlsOperation extends AbstractEditorOperation { - - /** - * The controls to change. - */ - @NotNull - private final Array controls; - - public ChangeControlsOperation(@NotNull final Array controls) { - this.controls = controls; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (final Control control : controls) { - redoChange(control); - } - - EXECUTOR_MANAGER.addFxTask(() -> { - controls.forEach(editor, (control, consumer) -> - consumer.notifyFxChangeProperty(control, getPropertyName())); - }); - }); - } - - /** - * Apply new changes to the control. - * - * @param control the control. - */ - @JmeThread - protected void redoChange(@NotNull final Control control) { - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (final Control control : controls) { - undoChange(control); - } - - EXECUTOR_MANAGER.addFxTask(() -> { - controls.forEach(editor, (control, consumer) -> - consumer.notifyFxChangeProperty(control, getPropertyName())); - }); - }); - } - - /** - * Revert changes for the control. - * - * @param control the control. - */ - @JmeThread - protected void undoChange(@NotNull final Control control) { - } - - /** - * Get the property name. - * - * @return the property name. - */ - @FxThread - protected @NotNull String getPropertyName() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java deleted file mode 100644 index c13dc531..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The operation to change a mesh of a model. - * - * @author JavaSaBr - */ -public class ChangeMeshOperation extends AbstractEditorOperation { - - /** - * The new mesh. - */ - @NotNull - private final Mesh newMesh; - - /** - * The previous mesh. - */ - @NotNull - private final Mesh oldMesh; - - /** - * The geometry. - */ - @NotNull - private final Geometry geometry; - - /** - * Instantiates a new Change mesh operation. - * - * @param newMesh the new mesh - * @param oldMesh the old mesh - * @param geometry the geometry - */ - public ChangeMeshOperation(@NotNull final Mesh newMesh, @NotNull final Mesh oldMesh, @NotNull final Geometry geometry) { - this.newMesh = newMesh; - this.oldMesh = oldMesh; - this.geometry = geometry; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - geometry.setMesh(newMesh); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(geometry, newMesh, "mesh")); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - geometry.setMesh(oldMesh); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(geometry, oldMesh, "mesh")); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/DisableAppStateOperation.java b/src/main/java/com/ss/editor/model/undo/impl/DisableAppStateOperation.java deleted file mode 100644 index 385ed1fa..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/DisableAppStateOperation.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to disable a {@link SceneAppState}. - * - * @author JavaSaBr - */ -public class DisableAppStateOperation extends AbstractEditorOperation { - - /** - * The scene app state. - */ - @NotNull - private final SceneAppState appState; - - public DisableAppStateOperation(@NotNull final SceneAppState appState) { - this.appState = appState; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - appState.setEnabled(false); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedAppState(appState)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - appState.setEnabled(true); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedAppState(appState)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java deleted file mode 100644 index 9005f075..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.util.ControlUtils; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of {@link AbstractEditorOperation} to disable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. - * - * @author JavaSaBr. - */ -public class DisableControlsOperation extends ChangeControlsOperation { - - public DisableControlsOperation(@NotNull final Array controls) { - super(controls); - } - - @Override - protected void redoChange(final @NotNull Control control) { - super.redoChange(control); - ControlUtils.setEnabled(control, false); - } - - @Override - protected void undoChange(final @NotNull Control control) { - super.undoChange(control); - ControlUtils.setEnabled(control, true); - } - - @Override - protected @NotNull String getPropertyName() { - return Messages.MODEL_PROPERTY_IS_ENABLED; - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/DisableSceneFilterOperation.java b/src/main/java/com/ss/editor/model/undo/impl/DisableSceneFilterOperation.java deleted file mode 100644 index bafdb13d..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/DisableSceneFilterOperation.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to disable a {@link SceneFilter}. - * - * @author JavaSaBr. - */ -public class DisableSceneFilterOperation extends AbstractEditorOperation { - - /** - * The scene filter. - */ - @NotNull - private final SceneFilter sceneFilter; - - public DisableSceneFilterOperation(@NotNull final SceneFilter sceneFilter) { - this.sceneFilter = sceneFilter; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneFilter.setEnabled(false); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedFilter(sceneFilter)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneFilter.setEnabled(true); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedFilter(sceneFilter)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/EnableAppStateOperation.java b/src/main/java/com/ss/editor/model/undo/impl/EnableAppStateOperation.java deleted file mode 100644 index 32bf621c..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/EnableAppStateOperation.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to enable a {@link SceneAppState}. - * - * @author JavaSaBr - */ -public class EnableAppStateOperation extends AbstractEditorOperation { - - /** - * The scene app state. - */ - @NotNull - private final SceneAppState appState; - - public EnableAppStateOperation(@NotNull final SceneAppState appState) { - this.appState = appState; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - appState.setEnabled(true); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedAppState(appState)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - appState.setEnabled(false); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedAppState(appState)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java deleted file mode 100644 index ec4c92bc..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.util.ControlUtils; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of {@link AbstractEditorOperation} to enable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. - * - * @author JavaSaBr. - */ -public class EnableControlsOperation extends ChangeControlsOperation { - - public EnableControlsOperation(@NotNull final Array controls) { - super(controls); - } - - @Override - protected void redoChange(final @NotNull Control control) { - super.redoChange(control); - ControlUtils.setEnabled(control, true); - } - - @Override - protected void undoChange(final @NotNull Control control) { - super.undoChange(control); - ControlUtils.setEnabled(control, false); - } - - @Override - protected @NotNull String getPropertyName() { - return Messages.MODEL_PROPERTY_IS_ENABLED; - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/EnableSceneFilterOperation.java b/src/main/java/com/ss/editor/model/undo/impl/EnableSceneFilterOperation.java deleted file mode 100644 index af713570..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/EnableSceneFilterOperation.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to enable a {@link SceneFilter}. - * - * @author JavaSaBr - */ -public class EnableSceneFilterOperation extends AbstractEditorOperation { - - /** - * The scene filter. - */ - @NotNull - private final SceneFilter sceneFilter; - - public EnableSceneFilterOperation(@NotNull final SceneFilter sceneFilter) { - this.sceneFilter = sceneFilter; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneFilter.setEnabled(true); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedFilter(sceneFilter)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneFilter.setEnabled(false); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyChangedFilter(sceneFilter)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java deleted file mode 100644 index f809c4b1..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The operation to move a node. - * - * @author JavaSaBr - */ -public class MoveChildOperation extends AbstractEditorOperation { - - /** - * The moved node. - */ - @NotNull - private final Spatial moved; - - /** - * The child index. - */ - private final int childIndex; - - /** - * The old parent. - */ - private Node oldParent; - - /** - * The new parent. - */ - private Node newParent; - - /** - * Instantiates a new Move child operation. - * - * @param moved the moved - * @param oldParent the old parent - * @param newParent the new parent - * @param childIndex the child index - */ - public MoveChildOperation(@NotNull final Spatial moved, @NotNull final Node oldParent, - @NotNull final Node newParent, final int childIndex) { - this.moved = moved; - this.oldParent = oldParent; - this.newParent = newParent; - this.childIndex = childIndex; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - newParent.attachChildAt(moved, 0); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxMoved(oldParent, newParent, moved, 0, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - oldParent.attachChildAt(moved, childIndex); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxMoved(newParent, oldParent, moved, childIndex, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java deleted file mode 100644 index 3744aaf6..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The operation to move a control. - * - * @author JavaSaBr - */ -public class MoveControlOperation extends AbstractEditorOperation { - - /** - * The moved node. - */ - @NotNull - private final Control moved; - - /** - * The old parent. - */ - private Spatial oldParent; - - /** - * The new parent. - */ - private Spatial newParent; - - /** - * Instantiates a new MoveControlOperation. - * - * @param moved the moved - * @param oldParent the old parent - * @param newParent the new parent - */ - public MoveControlOperation(@NotNull final Control moved, @NotNull final Spatial oldParent, - @NotNull final Spatial newParent) { - this.moved = moved; - this.oldParent = oldParent; - this.newParent = newParent; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - oldParent.removeControl(moved); - newParent.addControl(moved); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxMoved(oldParent, newParent, moved, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - newParent.removeControl(moved); - oldParent.addControl(moved); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxMoved(newParent, oldParent, moved, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java b/src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java deleted file mode 100644 index 89ae41b1..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The action to optimize geometry. - * - * @author JavaSaBr - */ -public class OptimizeGeometryOperation extends AbstractEditorOperation { - - /** - * The new element. - */ - @NotNull - private final Spatial newSpatial; - - /** - * The old element. - */ - @NotNull - private final Spatial oldSpatial; - - /** - * The parent node. - */ - @NotNull - private final Node parent; - - public OptimizeGeometryOperation(@NotNull final Spatial newSpatial, @NotNull final Spatial oldSpatial, - @NotNull final Node parent) { - this.newSpatial = newSpatial; - this.oldSpatial = oldSpatial; - this.parent = parent; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> apply(editor, oldSpatial, newSpatial)); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> apply(editor, newSpatial, oldSpatial)); - } - - /** - * Apply changes. - * - * @param consumer the change consumer. - * @param newSpatial the new spatial. - * @param oldSpatial the new old spatial. - */ - @JmeThread - private void apply(@NotNull final ModelChangeConsumer consumer, @NotNull final Spatial newSpatial, - @NotNull final Spatial oldSpatial) { - - final int index = parent.getChildIndex(newSpatial); - parent.detachChildAt(index); - parent.attachChildAt(oldSpatial, index); - - EXECUTOR_MANAGER.addFxTask(() -> consumer.notifyFxReplaced(parent, newSpatial, oldSpatial, true, false)); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveAppStateOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveAppStateOperation.java deleted file mode 100644 index 1c8d2e44..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveAppStateOperation.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove a {@link SceneAppState} from a {@link - * SceneNode}*. - * - * @author JavaSaBr. - */ -public class RemoveAppStateOperation extends AbstractEditorOperation { - - /** - * The new scene app state. - */ - @NotNull - private final SceneAppState newState; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - public RemoveAppStateOperation(@NotNull final SceneAppState newState, @NotNull final SceneNode sceneNode) { - this.newState = newState; - this.sceneNode = sceneNode; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.removeAppState(newState); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyRemovedAppState(newState)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addAppState(newState); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyAddedAppState(newState)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java deleted file mode 100644 index 9ded9abf..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove {@link Spatial} from the {@link Node}. - * - * @author JavaSaBr. - */ -public class RemoveChildOperation extends AbstractEditorOperation { - - /** - * The child to remove. - */ - @NotNull - private final Spatial child; - - /** - * The parent element. - */ - @NotNull - private final Node parent; - - /** - * The index of position in the parent. - */ - private final int childIndex; - - public RemoveChildOperation(@NotNull final Spatial child, @NotNull final Node parent) { - this.child = child; - this.parent = parent; - this.childIndex = parent.getChildIndex(child); - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.detachChild(child); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(parent, child)); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.attachChildAt(child, childIndex); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(parent, child, childIndex, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java deleted file mode 100644 index 196603da..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove a control from a node. - * - * @author JavaSaBr - */ -public class RemoveControlOperation extends AbstractEditorOperation { - - /** - * The control. - */ - @NotNull - private final Control control; - - /** - * The parent. - */ - @NotNull - private final Spatial parent; - - public RemoveControlOperation(@NotNull final Control control, @NotNull final Spatial parent) { - this.control = control; - this.parent = parent; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.removeControl(control); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(parent, control)); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.addControl(control); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(parent, control, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java deleted file mode 100644 index 255a2e94..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java +++ /dev/null @@ -1,197 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.jme3.light.Light; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove elements from a scene. - * - * @author JavaSaBr. - */ -public class RemoveElementsOperation extends AbstractEditorOperation { - - public static class Element { - - /** - * The element to remove. - */ - @NotNull - private final Object element; - - /** - * The element's parent. - */ - @NotNull - private final Object parent; - - /** - * The index of position in the parent. - */ - private int index; - - public Element(@NotNull final Object element, @NotNull final Object parent) { - this.element = element; - this.parent = parent; - this.index = -1; - } - - /** - * Get the element to remove. - * - * @return the element to remove. - */ - private @NotNull Object getElement() { - return element; - } - - /** - * Get the element's parent. - * - * @return the element's parent. - */ - private @NotNull Object getParent() { - return parent; - } - - /** - * Get the index of position in the parent. - * - * @return the index of position in the parent. - */ - private int getIndex() { - return index; - } - - /** - * Set the index of position in the parent. - * - * @param index the index of position in the parent. - */ - private void setIndex(final int index) { - this.index = index; - } - } - - /** - * The elements to remove. - */ - @NotNull - private final Array elements; - - public RemoveElementsOperation(@NotNull final Array elements) { - this.elements = elements; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (final Element element : elements) { - - final Object toRemove = element.getElement(); - - if (toRemove instanceof Spatial) { - removeSpatial(element, (Spatial) toRemove); - } else if (toRemove instanceof Light) { - removeLight(element, (Light) toRemove); - } else if (toRemove instanceof Animation) { - removeAnimation(element, (Animation) toRemove); - } else if (toRemove instanceof Control) { - removeControl(element, (Control) toRemove); - } - } - - EXECUTOR_MANAGER.addFxTask(() -> { - elements.forEach(editor, (element, consumer) -> - consumer.notifyFxRemovedChild(element.getParent(), element.getElement())); - }); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (final Element element : elements) { - - final Object toRestore = element.getElement(); - - if (toRestore instanceof Spatial) { - restoreSpatial(element, (Spatial) toRestore); - } else if (toRestore instanceof Light) { - restoreLight(element, (Light) toRestore); - } else if (toRestore instanceof Animation) { - restoreAnimation(element, (Animation) toRestore); - } else if (toRestore instanceof Control) { - restoreControl(element, (Control) toRestore); - } - } - - EXECUTOR_MANAGER.addFxTask(() -> { - elements.forEach(editor, (element, consumer) -> - consumer.notifyFxAddedChild(element.getParent(), element.getElement(), element.getIndex(), false)); - }); - }); - } - - @JmeThread - private void removeSpatial(@NotNull final Element element, @NotNull final Spatial toRemove) { - final Node parent = (Node) element.getParent(); - element.setIndex(parent.getChildIndex(toRemove)); - parent.detachChild(toRemove); - } - - @JmeThread - private void restoreSpatial(@NotNull final Element element, @NotNull final Spatial toRestore) { - final Node parent = (Node) element.getParent(); - parent.attachChildAt(toRestore, element.getIndex()); - } - - @JmeThread - private void removeControl(@NotNull final Element element, @NotNull final Control toRemove) { - final Spatial parent = (Spatial) element.getParent(); - parent.removeControl(toRemove); - } - - @JmeThread - private void restoreControl(@NotNull final Element element, @NotNull final Control toRestore) { - final Spatial parent = (Spatial) element.getParent(); - parent.addControl(toRestore); - } - - @JmeThread - private void removeLight(@NotNull final Element element, @NotNull final Light toRemove) { - final Spatial parent = (Spatial) element.getParent(); - parent.removeLight(toRemove); - } - - @JmeThread - private void restoreLight(@NotNull final Element element, @NotNull final Light toRestore) { - final Spatial parent = (Spatial) element.getParent(); - parent.addLight(toRestore); - } - - @JmeThread - private void removeAnimation(@NotNull final Element element, @NotNull final Animation toRemove) { - final AnimControl parent = (AnimControl) element.getParent(); - parent.removeAnim(toRemove); - } - - @JmeThread - private void restoreAnimation(@NotNull final Element element, @NotNull final Animation toRestore) { - final AnimControl parent = (AnimControl) element.getParent(); - parent.addAnim(toRestore); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java deleted file mode 100644 index 2b338ba7..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.light.Light; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove a {@link Light} from the {@link Spatial}. - * - * @author JavaSaBr. - */ -public class RemoveLightOperation extends AbstractEditorOperation { - - /** - * The light to remove. - */ - @NotNull - private final Light light; - - /** - * The parent. - */ - @NotNull - private final Node parent; - - public RemoveLightOperation(@NotNull final Light light, @NotNull final Node parent) { - this.light = light; - this.parent = parent; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.removeLight(light); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(parent, light)); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - parent.addLight(light); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(parent, light, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveSceneFilterOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveSceneFilterOperation.java deleted file mode 100644 index 1f0fcfcc..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveSceneFilterOperation.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove a {@link SceneFilter} from a {@link SceneNode}. - * - * @author JavaSaBr. - */ -public class RemoveSceneFilterOperation extends AbstractEditorOperation { - - /** - * The new scene filter. - */ - @NotNull - private final SceneFilter sceneFilter; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - public RemoveSceneFilterOperation(@NotNull final SceneFilter sceneFilter, @NotNull final SceneNode sceneNode) { - this.sceneFilter = sceneFilter; - this.sceneNode = sceneNode; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.removeFilter(sceneFilter); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyRemovedFilter(sceneFilter)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final SceneChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addFilter(sceneFilter); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyAddedFilter(sceneFilter)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java deleted file mode 100644 index d66aaf9c..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.bullet.objects.VehicleWheel; -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The operation to remove a wheel from a vehicle control. - * - * @author JavaSaBr - */ -public class RemoveVehicleWheelOperation extends AbstractEditorOperation { - - /** - * The vehicle control. - */ - @NotNull - private final VehicleControl control; - - /** - * The connection point. - */ - @NotNull - private final Vector3f connectionPoint; - - /** - * The direction. - */ - @NotNull - private final Vector3f direction; - - /** - * The axle. - */ - @NotNull - private final Vector3f axle; - - /** - * The wheel. - */ - @Nullable - private VehicleWheel createdWheel; - - /** - * The rest length. - */ - private final float restLength; - - /** - * The wheel radius. - */ - private final float wheelRadius; - - /** - * The flag is front wheel. - */ - private final boolean isFrontWheel; - - public RemoveVehicleWheelOperation(@NotNull final VehicleControl control, @NotNull final VehicleWheel wheel) { - this.control = control; - this.connectionPoint = wheel.getLocation(); - this.direction = wheel.getDirection(); - this.axle = wheel.getAxle(); - this.restLength = wheel.getRestLength(); - this.wheelRadius = wheel.getRadius(); - this.isFrontWheel = wheel.isFrontWheel(); - this.createdWheel = wheel; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - for (int i = 0, length = control.getNumWheels(); i < length; i++) { - final VehicleWheel wheel = control.getWheel(i); - if (wheel == createdWheel) { - control.removeWheel(i); - break; - } - } - - final VehicleWheel toRemove = notNull(createdWheel); - - this.createdWheel = null; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(control, toRemove)); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final VehicleWheel vehicleWheel = control.addWheel(connectionPoint, direction, axle, restLength, - wheelRadius, isFrontWheel); - - this.createdWheel = vehicleWheel; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(control, vehicleWheel, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java deleted file mode 100644 index 43b1cc65..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.light.Light; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The operation to rename light. - */ -public class RenameLightOperation extends AbstractEditorOperation { - - /** - * The constant PROPERTY_NAME. - */ - public static final String PROPERTY_NAME = "name"; - - /** - * The old name. - */ - @NotNull - private final String oldName; - - /** - * The new name. - */ - @NotNull - private final String newName; - - /** - * The node. - */ - @NotNull - private final Light light; - - public RenameLightOperation(@NotNull final String oldName, @NotNull final String newName, @NotNull final Light light) { - this.oldName = oldName; - this.newName = newName; - this.light = light; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - light.setName(newName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(light, PROPERTY_NAME)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - light.setName(oldName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(light, PROPERTY_NAME)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java deleted file mode 100644 index ef1dd08c..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.ss.editor.model.undo.impl; - -import com.jme3.scene.Spatial; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; - -import org.jetbrains.annotations.NotNull; - -/** - * The operation to rename a node. - * - * @author JavaSaBr - */ -public class RenameNodeOperation extends AbstractEditorOperation { - - /** - * The constant PROPERTY_NAME. - */ - public static final String PROPERTY_NAME = "name"; - - /** - * The old name. - */ - @NotNull - private final String oldName; - - /** - * The new name. - */ - @NotNull - private final String newName; - - /** - * The node. - */ - @NotNull - private final Spatial spatial; - - public RenameNodeOperation(@NotNull final String oldName, @NotNull final String newName, @NotNull final Spatial spatial) { - this.oldName = oldName; - this.newName = newName; - this.spatial = spatial; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - spatial.setName(newName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(spatial, PROPERTY_NAME)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - spatial.setName(oldName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(spatial, PROPERTY_NAME)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java deleted file mode 100644 index f3dc624b..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ss.editor.model.undo.impl.animation; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add an animation. - * - * @author JavaSaBr - */ -public class AddAnimationNodeOperation extends AbstractEditorOperation { - - /** - * The animation control. - */ - @NotNull - private final AnimControl control; - - /** - * The animation. - */ - @NotNull - private final Animation animation; - - /** - * Instantiates a new Add animation node operation. - * - * @param animation the animation - * @param control the control - */ - public AddAnimationNodeOperation(@NotNull final Animation animation, @NotNull final AnimControl control) { - this.animation = animation; - this.control = control; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - control.addAnim(animation); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(control, animation, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - control.removeAnim(animation); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(control, animation)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java deleted file mode 100644 index a9980022..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.model.undo.impl.animation; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to delete an animation. - * - * @author JavaSaBr - */ -public class RemoveAnimationNodeOperation extends AbstractEditorOperation { - - /** - * The animation control. - */ - @NotNull - private final AnimControl control; - - /** - * The animation. - */ - @NotNull - private final Animation animation; - - public RemoveAnimationNodeOperation(@NotNull final Animation animation, @NotNull final AnimControl control) { - this.animation = animation; - this.control = control; - } - - @Override - @JmeThread - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - control.removeAnim(animation); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(control, animation)); - }); - } - - @Override - @JmeThread - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - control.addAnim(animation); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(control, animation, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java deleted file mode 100644 index 04cfeb8f..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ss.editor.model.undo.impl.animation; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.util.AnimationUtils; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} for editing name of an animation. - * - * @author JavaSaBr - */ -public class RenameAnimationNodeOperation extends AbstractEditorOperation { - - /** - * The old name. - */ - @NotNull - private final String oldName; - - /** - * The new name. - */ - @NotNull - private final String newName; - - /** - * The animation control. - */ - @NotNull - private final AnimControl control; - - /** - * Instantiates a new Rename animation node operation. - * - * @param oldName the old name - * @param newName the new name - * @param control the control - */ - public RenameAnimationNodeOperation(@NotNull final String oldName, @NotNull final String newName, - @NotNull final AnimControl control) { - this.oldName = oldName; - this.newName = newName; - this.control = control; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - final Animation anim = control.getAnim(oldName); - AnimationUtils.changeName(control, anim, oldName, newName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(control, anim, "name")); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - final Animation anim = control.getAnim(newName); - AnimationUtils.changeName(control, anim, newName, oldName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(control, anim, "name")); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java deleted file mode 100644 index 48c2fe9f..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.model.undo.impl.emitter; - -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.shapes.EmitterShape; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} for changing a shape in the {@link ParticleEmitter}. - * - * @author JavaSaBr. - */ -public class ChangeEmitterShapeOperation extends AbstractEditorOperation { - - /** - * The emitter. - */ - @NotNull - private final ParticleEmitter emitter; - - /** - * The prev shape. - */ - @NotNull - private volatile EmitterShape prevShape; - - public ChangeEmitterShapeOperation(@NotNull final EmitterShape newShape, @NotNull final ParticleEmitter emitter) { - this.prevShape = newShape; - this.emitter = emitter; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> switchShape(editor)); - } - - private void switchShape(final @NotNull ModelChangeConsumer editor) { - - final EmitterShape shape = emitter.getShape(); - final EmitterShape newShape = prevShape; - prevShape = shape; - emitter.setShape(newShape); - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxReplaced(emitter, prevShape, newShape, true, true)); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> switchShape(editor)); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java deleted file mode 100644 index add6f942..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.ss.editor.model.undo.impl.emitter; - -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to change a {@link ParticleInfluencer} to a {@link - * ParticleEmitter}. - * - * @author JavaSaBr. - */ -public class ChangeParticleInfluencerOperation extends AbstractEditorOperation { - - /** - * The particle emitter. - */ - @NotNull - private final ParticleEmitter emitter; - - /** - * The prev influencer. - */ - @NotNull - private ParticleInfluencer prevInfluencer; - - /** - * Instantiates a new Add particle influencer operation. - * - * @param influencer the influencer - * @param emitter the particle emitter - */ - public ChangeParticleInfluencerOperation(@NotNull final ParticleInfluencer influencer, - @NotNull final ParticleEmitter emitter) { - this.prevInfluencer = influencer; - this.emitter = emitter; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> switchInfluencer(editor)); - } - - private void switchInfluencer(final @NotNull ModelChangeConsumer editor) { - - final ParticleInfluencer influencer = emitter.getParticleInfluencer(); - final ParticleInfluencer newInfluencer = prevInfluencer; - prevInfluencer = influencer; - emitter.setParticleInfluencer(newInfluencer); - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxReplaced(emitter, prevInfluencer, newInfluencer, true, true)); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> switchInfluencer(editor)); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java deleted file mode 100644 index 976eb0d8..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.model.undo.impl.scene; - -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a layer to a scene. - * - * @author JavaSaBr - */ -public class AddSceneLayerOperation extends AbstractEditorOperation { - - /** - * The layers root. - */ - @NotNull - private final LayersRoot layersRoot; - - /** - * The new layer. - */ - @NotNull - private final SceneLayer layer; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - /** - * Instantiates a new Add scene layer operation. - * - * @param layersRoot the layers root - * @param layer the layer - * @param sceneNode the scene node - */ - public AddSceneLayerOperation(final @NotNull LayersRoot layersRoot, @NotNull final SceneLayer layer, - @NotNull final SceneNode sceneNode) { - this.layersRoot = layersRoot; - this.layer = layer; - this.sceneNode = sceneNode; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addLayer(layer); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(layersRoot, layer, -1, true)); - }); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.removeLayer(layer); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(layersRoot, layer)); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java deleted file mode 100644 index b781ec4d..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.ss.editor.model.undo.impl.scene; - -import com.jme3.scene.Spatial; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.extension.scene.SceneLayer; - -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link AbstractEditorOperation} to add a layer to a scene. - * - * @author JavaSaBr - */ -public class ChangeVisibleSceneLayerOperation extends AbstractEditorOperation { - - /** - * The layer. - */ - @NotNull - private final SceneLayer layer; - - /** - * The flag is need to show. - */ - private boolean needShow; - - /** - * Instantiates a new Change visible scene layer operation. - * - * @param layer the layer - * @param needShow the need show - */ - public ChangeVisibleSceneLayerOperation(@NotNull final SceneLayer layer, final boolean needShow) { - this.layer = layer; - this.needShow = needShow; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final Spatial currentModel = editor.getCurrentModel(); - - if (needShow && !layer.isShowed()) { - layer.show(); - currentModel.depthFirstTraversal(this::updateSpatial); - } else if (!needShow && layer.isShowed()) { - layer.hide(); - currentModel.depthFirstTraversal(this::updateSpatial); - } - - needShow = !needShow; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(layer, "Showed")); - }); - } - - private void updateSpatial(@NotNull final Spatial spatial) { - if (SceneLayer.getLayer(spatial) != layer) return; - spatial.setVisible(layer.isShowed()); - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final Spatial currentModel = editor.getCurrentModel(); - - if (needShow && !layer.isShowed()) { - layer.show(); - currentModel.depthFirstTraversal(this::updateSpatial); - } else if (!needShow && layer.isShowed()) { - layer.hide(); - currentModel.depthFirstTraversal(this::updateSpatial); - } - - needShow = !needShow; - - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(layer, "Showed")); - }); - } -} diff --git a/src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java deleted file mode 100644 index b449c297..00000000 --- a/src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.ss.editor.model.undo.impl.scene; - -import com.jme3.scene.Spatial; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; - -import org.jetbrains.annotations.NotNull; - -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; - -/** - * The implementation of the {@link AbstractEditorOperation} to remove a layer from a scene. - * - * @author JavaSaBr - */ -public class RemoveSceneLayerOperation extends AbstractEditorOperation { - - /** - * The list with spatials which uses this layer. - */ - @NotNull - private final Array toRevert; - - /** - * The layer layersRoot. - */ - @NotNull - private final LayersRoot layersRoot; - - /** - * The removed layer. - */ - @NotNull - private final SceneLayer layer; - - /** - * The scene node. - */ - @NotNull - private final SceneNode sceneNode; - - /** - * Instantiates a new Remove scene layer operation. - * - * @param layersRoot the layers root - * @param layer the layer - * @param sceneNode the scene node - */ - public RemoveSceneLayerOperation(final @NotNull LayersRoot layersRoot, @NotNull final SceneLayer layer, - @NotNull final SceneNode sceneNode) { - this.toRevert = ArrayFactory.newArray(Spatial.class); - this.layersRoot = layersRoot; - this.layer = layer; - this.sceneNode = sceneNode; - } - - @Override - protected void redoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - final Spatial currentModel = editor.getCurrentModel(); - currentModel.depthFirstTraversal(this::clean); - sceneNode.removeLayer(layer); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxRemovedChild(layersRoot, layer)); - }); - } - - private void clean(@NotNull final Spatial spatial) { - final SceneLayer currentLayer = SceneLayer.getLayer(spatial); - if (currentLayer == layer) { - toRevert.add(spatial); - SceneLayer.setLayer(null, spatial); - spatial.setVisible(true); - } - } - - @Override - protected void undoImpl(@NotNull final ModelChangeConsumer editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - sceneNode.addLayer(layer); - toRevert.forEach(spatial -> SceneLayer.setLayer(layer, spatial)); - toRevert.forEach(spatial -> spatial.setVisible(layer.isShowed())); - toRevert.clear(); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxAddedChild(layersRoot, layer, -1, false)); - }); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/Editor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/Editor3DPart.java deleted file mode 100644 index 1c6dbdcc..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/Editor3DPart.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ss.editor.part3d.editor; - -import com.jme3.app.state.AppState; - -/** - * The interface to implement a 3D part of editor. - * - * @author JavaSaBr - */ -public interface Editor3DPart extends AppState { -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/AbstractEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/AbstractEditor3DPart.java deleted file mode 100644 index 3702cea6..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/AbstractEditor3DPart.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ss.editor.part3d.editor.impl; - -import com.jme3.app.state.AbstractAppState; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.part3d.editor.Editor3DPart; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import org.jetbrains.annotations.NotNull; - -/** - * The base implementation of the {@link Editor3DPart} to use inside {@link FileEditor}. - * - * @param the type of file editor - * @author JavaSaBr - */ -public abstract class AbstractEditor3DPart extends AbstractAppState implements Editor3DPart { - - /** - * The logger. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(Editor3DPart.class); - - /** - * The executor manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The owner editor. - */ - @NotNull - private final T fileEditor; - - /** - * The root node. - */ - @NotNull - private final Node stateNode; - - public AbstractEditor3DPart(@NotNull final T fileEditor) { - this.fileEditor = fileEditor; - this.stateNode = new Node(getClass().getSimpleName()); - } - - /** - * Get the state node. - * - * @return the root node. - */ - @FromAnyThread - protected @NotNull Node getStateNode() { - return stateNode; - } - - /** - * Get the file editor. - * - * @return the owner editor. - */ - @FromAnyThread - protected @NotNull T getFileEditor() { - return fileEditor; - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/AdvancedAbstractEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/AdvancedAbstractEditor3DPart.java deleted file mode 100644 index f98394e1..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/AdvancedAbstractEditor3DPart.java +++ /dev/null @@ -1,1295 +0,0 @@ -package com.ss.editor.part3d.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.array.ArrayFactory.toArray; -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.input.InputManager; -import com.jme3.input.KeyInput; -import com.jme3.input.MouseInput; -import com.jme3.input.controls.*; -import com.jme3.light.DirectionalLight; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.Config; -import com.ss.editor.model.EditorCamera; -import com.ss.editor.plugin.api.RenderFilterExtension; -import com.ss.editor.part3d.editor.Editor3DPart; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; -import com.ss.rlib.common.function.BooleanFloatConsumer; -import com.ss.rlib.common.function.FloatFloatConsumer; -import com.ss.rlib.common.logging.LoggerLevel; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * The base implementation of the {@link Editor3DPart} for a file editor. - * - * @param the type of a file editor. - * @author JavaSaBr - */ -public abstract class AdvancedAbstractEditor3DPart extends AbstractEditor3DPart { - - /** - * The constant TRIGGERS. - */ - @NotNull - protected static final ObjectDictionary TRIGGERS = DictionaryFactory.newObjectDictionary(); - - /** - * The constant MULTI_TRIGGERS. - */ - @NotNull - protected static final ObjectDictionary MULTI_TRIGGERS = DictionaryFactory.newObjectDictionary(); - - /** - * The constant MOUSE_RIGHT_CLICK. - */ - @NotNull - protected static final String MOUSE_RIGHT_CLICK = "SSEditor.editorState.mouseRightClick"; - - /** - * The constant MOUSE_LEFT_CLICK. - */ - @NotNull - protected static final String MOUSE_LEFT_CLICK = "SSEditor.editorState.mouseLeftClick"; - - /** - * The constant MOUSE_MIDDLE_CLICK. - */ - @NotNull - protected static final String MOUSE_MIDDLE_CLICK = "SSEditor.editorState.mouseMiddleClick"; - - /** - * The constant MOUSE_X_AXIS. - */ - @NotNull - protected static final String MOUSE_X_AXIS = "SSEditor.editorState.mouseXAxis"; - - /** - * The constant MOUSE_X_AXIS_NEGATIVE. - */ - @NotNull - protected static final String MOUSE_X_AXIS_NEGATIVE = "SSEditor.editorState.mouseXAxisNegative"; - - /** - * The constant MOUSE_Y_AXIS. - */ - @NotNull - protected static final String MOUSE_Y_AXIS = "SSEditor.editorState.mouseYAxis"; - - /** - * The constant MOUSE_Y_AXIS_NEGATIVE. - */ - @NotNull - protected static final String MOUSE_Y_AXIS_NEGATIVE = "SSEditor.editorState.mouseYAxisNegative"; - - /** - * The constant MOUSE_MOVE_CAMERA_X_AXIS. - */ - @NotNull - protected static final String MOUSE_MOVE_CAMERA_X_AXIS = "SSEditor.editorState.mouseMoveCameraXAxis"; - - /** - * The constant MOUSE_MOVE_CAMERA_X_AXIS_NEGATIVE. - */ - @NotNull - protected static final String MOUSE_MOVE_CAMERA_X_AXIS_NEGATIVE = "SSEditor.editorState.mouseMoveCameraXAxisNegative"; - - /** - * The constant MOUSE_MOVE_CAMERA_Y_AXIS. - */ - @NotNull - protected static final String MOUSE_MOVE_CAMERA_Y_AXIS = "SSEditor.editorState.mouseMoveCameraYAxis"; - - /** - * The constant MOUSE_MOVE_CAMERA_Y_AXIS_NEGATIVE. - */ - @NotNull - protected static final String MOUSE_MOVE_CAMERA_Y_AXIS_NEGATIVE = "SSEditor.editorState.mouseMoveCameraYAxisNegative"; - - /** - * The constant KEY_CTRL. - */ - @NotNull - protected static final String KEY_CTRL = "SSEditor.editorState.keyCtrl"; - - /** - * The constant KEY_ALT. - */ - @NotNull - protected static final String KEY_ALT = "SSEditor.editorState.keyAlt"; - - /** - * The constant KEY_SHIFT. - */ - @NotNull - protected static final String KEY_SHIFT = "SSEditor.editorState.keyShift"; - - /** - * The constant KEY_CTRL_S. - */ - @NotNull - protected static final String KEY_CTRL_S = "SSEditor.editorState.Ctrl.S"; - - /** - * The constant KEY_CTRL_Z. - */ - @NotNull - protected static final String KEY_CTRL_Z = "SSEditor.editorState.Ctrl.Z"; - - /** - * The constant KEY_CTRL_Y. - */ - @NotNull - protected static final String KEY_CTRL_Y = "SSEditor.editorState.Ctrl.Y"; - - /** - * The constant KEY_FLY_CAMERA_W. - */ - @NotNull - protected static final String KEY_FLY_CAMERA_W = "SSEditor.editorState.keyFlyCameraW"; - - /** - * The constant KEY_FLY_CAMERA_S. - */ - @NotNull - protected static final String KEY_FLY_CAMERA_S = "SSEditor.editorState.keyFlyCameraS"; - - /** - * The constant KEY_FLY_CAMERA_A. - */ - @NotNull - protected static final String KEY_FLY_CAMERA_A = "SSEditor.editorState.keyFlyCameraA"; - - /** - * The constant KEY_FLY_CAMERA_D. - */ - @NotNull - protected static final String KEY_FLY_CAMERA_D = "SSEditor.editorState.keyFlyCameraD"; - - /** - * The constant KEY_NUM_1. - */ - @NotNull - protected static final String KEY_NUM_1 = "SSEditor.editorState.num1"; - - /** - * The constant KEY_NUM_2. - */ - @NotNull - protected static final String KEY_NUM_2 = "SSEditor.editorState.num2"; - - /** - * The constant KEY_NUM_3. - */ - @NotNull - protected static final String KEY_NUM_3 = "SSEditor.editorState.num3"; - - /** - * The constant KEY_NUM_4. - */ - @NotNull - protected static final String KEY_NUM_4 = "SSEditor.editorState.num4"; - - /** - * The constant KEY_NUM_5. - */ - @NotNull - protected static final String KEY_NUM_5 = "SSEditor.editorState.num5"; - - /** - * The constant KEY_NUM_6. - */ - @NotNull - protected static final String KEY_NUM_6 = "SSEditor.editorState.num6"; - - /** - * The constant KEY_NUM_7. - */ - @NotNull - protected static final String KEY_NUM_7 = "SSEditor.editorState.num7"; - - /** - * The constant KEY_NUM_8. - */ - @NotNull - protected static final String KEY_NUM_8 = "SSEditor.editorState.num8"; - - /** - * The constant KEY_NUM_9. - */ - @NotNull - protected static final String KEY_NUM_9 = "SSEditor.editorState.num9"; - - static { - TRIGGERS.put(MOUSE_X_AXIS, new MouseAxisTrigger(MouseInput.AXIS_X, false)); - TRIGGERS.put(MOUSE_X_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_X, true)); - TRIGGERS.put(MOUSE_Y_AXIS, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); - TRIGGERS.put(MOUSE_Y_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); - TRIGGERS.put(MOUSE_MOVE_CAMERA_X_AXIS, new MouseAxisTrigger(MouseInput.AXIS_X, false)); - TRIGGERS.put(MOUSE_MOVE_CAMERA_X_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_X, true)); - TRIGGERS.put(MOUSE_MOVE_CAMERA_Y_AXIS, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); - TRIGGERS.put(MOUSE_MOVE_CAMERA_Y_AXIS_NEGATIVE, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); - - TRIGGERS.put(MOUSE_RIGHT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); - TRIGGERS.put(MOUSE_LEFT_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); - TRIGGERS.put(MOUSE_MIDDLE_CLICK, new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); - - MULTI_TRIGGERS.put(KEY_CTRL, toArray(new KeyTrigger(KeyInput.KEY_RCONTROL), new KeyTrigger(KeyInput.KEY_LCONTROL))); - MULTI_TRIGGERS.put(KEY_SHIFT, toArray(new KeyTrigger(KeyInput.KEY_RSHIFT), new KeyTrigger(KeyInput.KEY_LSHIFT))); - MULTI_TRIGGERS.put(KEY_ALT, toArray(new KeyTrigger(KeyInput.KEY_RMENU), new KeyTrigger(KeyInput.KEY_LMENU))); - - TRIGGERS.put(KEY_CTRL_S, new KeyTrigger(KeyInput.KEY_S)); - TRIGGERS.put(KEY_CTRL_Z, new KeyTrigger(KeyInput.KEY_Z)); - TRIGGERS.put(KEY_CTRL_Y, new KeyTrigger(KeyInput.KEY_Y)); - - TRIGGERS.put(KEY_FLY_CAMERA_W, new KeyTrigger(KeyInput.KEY_W)); - TRIGGERS.put(KEY_FLY_CAMERA_S, new KeyTrigger(KeyInput.KEY_S)); - TRIGGERS.put(KEY_FLY_CAMERA_A, new KeyTrigger(KeyInput.KEY_A)); - TRIGGERS.put(KEY_FLY_CAMERA_D, new KeyTrigger(KeyInput.KEY_D)); - - TRIGGERS.put(KEY_NUM_1, new KeyTrigger(KeyInput.KEY_NUMPAD1)); - TRIGGERS.put(KEY_NUM_2, new KeyTrigger(KeyInput.KEY_NUMPAD2)); - TRIGGERS.put(KEY_NUM_3, new KeyTrigger(KeyInput.KEY_NUMPAD3)); - TRIGGERS.put(KEY_NUM_4, new KeyTrigger(KeyInput.KEY_NUMPAD4)); - TRIGGERS.put(KEY_NUM_5, new KeyTrigger(KeyInput.KEY_NUMPAD5)); - TRIGGERS.put(KEY_NUM_6, new KeyTrigger(KeyInput.KEY_NUMPAD6)); - TRIGGERS.put(KEY_NUM_7, new KeyTrigger(KeyInput.KEY_NUMPAD7)); - TRIGGERS.put(KEY_NUM_8, new KeyTrigger(KeyInput.KEY_NUMPAD8)); - TRIGGERS.put(KEY_NUM_9, new KeyTrigger(KeyInput.KEY_NUMPAD9)); - } - - /** - * The table of action handlers. - */ - @NotNull - private final ObjectDictionary actionHandlers; - - /** - * The table of analog handlers. - */ - @NotNull - private final ObjectDictionary analogHandlers; - - /** - * The action scene listeners. - */ - @NotNull - protected final ActionListener actionListener; - - /** - * The analog scene listeners. - */ - @NotNull - protected final AnalogListener analogListener; - - /** - * The editor camera. - */ - @Nullable - private final EditorCamera editorCamera; - - /** - * The light of the camera. - */ - @Nullable - private final DirectionalLight lightForCamera; - - /** - * The previous camera location. - */ - @NotNull - private final Vector3f prevCameraLocation; - - /** - * The state of camera keys. - */ - @NotNull - private final boolean[] cameraKeysState; - - /** - * The flag of moving camera. - */ - @NotNull - private AtomicInteger cameraMoving; - - /** - * The current state manager. - */ - @Nullable - protected AppStateManager stateManager; - - /** - * The previous camera zoom. - */ - private float prevTargetDistance; - - /** - * The previous vertical camera rotation. - */ - private float prevVRotation; - - /** - * The previous horizontal camera rotation. - */ - private float prevHRotation; - - /** - * The previous camera speed. - */ - private float prevCameraSpeed; - - /** - * The camera speed. - */ - private float cameraSpeed; - - /** - * Is control pressed. - */ - private boolean controlDown; - - /** - * Is alt pressed. - */ - private boolean altDown; - - /** - * Is shift pressed. - */ - private boolean shiftDown; - - /** - * Is left button pressed. - */ - private boolean buttonLeftDown; - - /** - * Is right button pressed. - */ - private boolean buttonRightDown; - - /** - * Is middle button pressed. - */ - private boolean buttonMiddleDown; - - public AdvancedAbstractEditor3DPart(@NotNull final T fileEditor) { - super(fileEditor); - this.cameraMoving = new AtomicInteger(); - this.editorCamera = needEditorCamera() ? createEditorCamera() : null; - this.lightForCamera = needLightForCamera() ? createLightForCamera() : null; - this.prevCameraLocation = new Vector3f(); - this.cameraKeysState = new boolean[4]; - this.cameraSpeed = 1F; - - if (lightForCamera != null) { - final Node stateNode = getStateNode(); - stateNode.addLight(lightForCamera); - } - - this.analogListener = this::onAnalogImpl; - this.actionListener = this::onActionImpl; - this.actionHandlers = DictionaryFactory.newObjectDictionary(); - this.analogHandlers = DictionaryFactory.newObjectDictionary(); - - registerActionHandlers(actionHandlers); - registerAnalogHandlers(analogHandlers); - } - - /** - * Register action handlers. - * - * @param actionHandlers the action handlers - */ - @JmeThread - protected void registerActionHandlers(@NotNull final ObjectDictionary actionHandlers) { - actionHandlers.put(KEY_ALT, (isPressed, tpf) -> setAltDown(isPressed)); - actionHandlers.put(MOUSE_LEFT_CLICK, (isPressed, tpf) -> setButtonLeftDown(isPressed)); - actionHandlers.put(MOUSE_RIGHT_CLICK, (isPressed, tpf) -> setButtonRightDown(isPressed)); - actionHandlers.put(KEY_NUM_1, (isPressed, tpf) -> rotateTo(EditorCamera.Perspective.BACK, isPressed)); - actionHandlers.put(KEY_NUM_3, (isPressed, tpf) -> rotateTo(EditorCamera.Perspective.RIGHT, isPressed)); - actionHandlers.put(KEY_NUM_7, (isPressed, tpf) -> rotateTo(EditorCamera.Perspective.TOP, isPressed)); - actionHandlers.put(KEY_NUM_9, (isPressed, tpf) -> rotateTo(EditorCamera.Perspective.BOTTOM, isPressed)); - actionHandlers.put(KEY_NUM_2, (isPressed, tpf) -> rotateTo(EditorCamera.Direction.BOTTOM, isPressed)); - actionHandlers.put(KEY_NUM_8, (isPressed, tpf) -> rotateTo(EditorCamera.Direction.TOP, isPressed)); - actionHandlers.put(KEY_NUM_4, (isPressed, tpf) -> rotateTo(EditorCamera.Direction.LEFT, isPressed)); - actionHandlers.put(KEY_NUM_6, (isPressed, tpf) -> rotateTo(EditorCamera.Direction.RIGHT, isPressed)); - - actionHandlers.put(MOUSE_MIDDLE_CLICK, (isPressed, tpf) -> { - setButtonMiddleDown(isPressed); - if (isCameraMoving() && !isPressed) finishCameraMoving(0, true); - }); - - actionHandlers.put(KEY_CTRL, (isPressed, tpf) -> { - setControlDown(isPressed); - if (isCameraMoving() && isPressed && cameraSpeed > 0) { - cameraSpeed = Math.max(cameraSpeed - 0.4F, 0.1F); - } - }); - - actionHandlers.put(KEY_SHIFT, (isPressed, tpf) -> { - setShiftDown(isPressed); - if (isCameraMoving() && isPressed && cameraSpeed > 0) { - cameraSpeed += 0.4F; - } - }); - - actionHandlers.put(KEY_CTRL_Z, (isPressed, tpf) -> { - if (!isPressed && isControlDown()) undo(); - }); - actionHandlers.put(KEY_CTRL_Y, (isPressed, tpf) -> { - if (!isPressed && isControlDown()) redo(); - }); - - actionHandlers.put(KEY_FLY_CAMERA_A, (isPressed, tpf) -> { - if (isButtonMiddleDown()) moveSideCamera(tpf, true, isPressed, 0); - }); - actionHandlers.put(KEY_FLY_CAMERA_D, (isPressed, tpf) -> { - if (isButtonMiddleDown()) moveSideCamera(-tpf, true, isPressed, 1); - }); - actionHandlers.put(KEY_FLY_CAMERA_W, (isPressed, tpf) -> { - if (isButtonMiddleDown()) moveDirectionCamera(tpf, true, isPressed, 2); - }); - actionHandlers.put(KEY_FLY_CAMERA_S, (isPressed, tpf) -> { - if (isButtonMiddleDown()) moveDirectionCamera(-tpf, true, isPressed, 3); - }); - - actionHandlers.put(KEY_CTRL_S, (isPressed, tpf) -> { - final FileEditor fileEditor = getFileEditor(); - if (isPressed && isControlDown() && fileEditor.isDirty()) { - EXECUTOR_MANAGER.addFxTask(fileEditor::save); - } - }); - } - - /** - * Register analog handlers. - * - * @param analogHandlers the analog handlers - */ - @JmeThread - protected void registerAnalogHandlers(@NotNull final ObjectDictionary analogHandlers) { - analogHandlers.put(MOUSE_X_AXIS, (value, tpf) -> moveXMouse(value)); - analogHandlers.put(MOUSE_X_AXIS_NEGATIVE, (value, tpf) -> moveXMouse(-value)); - analogHandlers.put(MOUSE_Y_AXIS, (value, tpf) -> moveYMouse(-value)); - analogHandlers.put(MOUSE_Y_AXIS_NEGATIVE, (value, tpf) -> moveYMouse(value)); - } - - /** - * Handle analog events. - */ - @JmeThread - private void onAnalogImpl(@NotNull final String name, final float value, final float tpf) { - final FloatFloatConsumer handler = analogHandlers.get(name); - if (handler != null) handler.accept(value, tpf); - } - - /** - * Move a mouse on X axis. - * - * @param value the value to move. - */ - @JmeThread - protected void moveXMouse(final float value) { - } - - /** - * Move a mouse on Y axis. - * - * @param value the value to move. - */ - @JmeThread - protected void moveYMouse(final float value) { - } - - /** - * @return true if the camera is moving now. - */ - @JmeThread - public boolean isCameraMoving() { - return cameraMoving.get() != 0; - } - - /** - * @return the state of camera keys. - */ - @JmeThread - private @NotNull boolean[] getCameraKeysState() { - return cameraKeysState; - } - - /** - * Start to move the camera. - */ - @JmeThread - private void startCameraMoving(final int key) { - - if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { - LOGGER.debug(this, "start camera moving[" + cameraMoving + "] for key " + key); - } - - if (cameraMoving.get() == 0) { - - final Camera camera = EditorUtil.getGlobalCamera(); - final Node nodeForCamera = getNodeForCamera(); - nodeForCamera.setLocalTranslation(camera.getLocation()); - - final EditorCamera editorCamera = notNull(getEditorCamera()); - editorCamera.setTargetDistance(0); - } - - final boolean[] cameraKeysState = getCameraKeysState(); - - if (!cameraKeysState[key]) { - cameraKeysState[key] = true; - cameraMoving.incrementAndGet(); - } - } - - /** - * Finish to move the camera. - */ - @JmeThread - private void finishCameraMoving(final int key, final boolean force) { - - final boolean[] cameraKeysState = getCameraKeysState(); - - if (Config.DEV_CAMERA_DEBUG && LOGGER.isEnabled(LoggerLevel.DEBUG)) { - LOGGER.debug(this, "finish camera moving[" + cameraMoving + "] for key " + key + ", force = " + force); - } - - cameraKeysState[key] = false; - - if (cameraMoving.get() == 0) return; - - if (force) { - cameraMoving.set(0); - for (int i = 0; i < cameraKeysState.length; i++) { - cameraKeysState[i] = false; - } - } else { - cameraMoving.decrementAndGet(); - } - } - - /** - * Move a camera to direction. - * - * @param value the value to move. - */ - @JmeThread - private void moveDirectionCamera(final float value, final boolean isAction, final boolean isPressed, final int key) { - - if (!canCameraMove()) { - return; - } else if (isAction && isPressed) { - startCameraMoving(key); - } else if (isAction) { - finishCameraMoving(key, false); - } - - if (!isCameraMoving() || isAction) { - return; - } - - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera == null) { - return; - } - - final Camera camera = EditorUtil.getGlobalCamera(); - final Node nodeForCamera = getNodeForCamera(); - - final LocalObjects local = LocalObjects.get(); - final Vector3f direction = camera.getDirection(local.nextVector()); - direction.multLocal(value * cameraSpeed); - direction.addLocal(nodeForCamera.getLocalTranslation()); - - nodeForCamera.setLocalTranslation(direction); - } - - /** - * Move a camera to side. - * - * @param value the value to move. - */ - @JmeThread - private void moveSideCamera(final float value, final boolean isAction, final boolean isPressed, final int key) { - - if (!canCameraMove()) { - return; - } else if (isAction && isPressed) { - startCameraMoving(key); - } else if (isAction) { - finishCameraMoving(key, false); - } - - if (!isCameraMoving() || isAction) { - return; - } - - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera == null) { - return; - } - - final Camera camera = EditorUtil.getGlobalCamera(); - final Node nodeForCamera = getNodeForCamera(); - - final LocalObjects local = LocalObjects.get(); - final Vector3f left = camera.getLeft(local.nextVector()); - left.multLocal(value * cameraSpeed); - left.addLocal(nodeForCamera.getLocalTranslation()); - - nodeForCamera.setLocalTranslation(left); - } - - @JmeThread - private boolean canCameraMove() { - return needMovableCamera() && isButtonMiddleDown(); - } - - /** - * Need movable camera boolean. - * - * @return true if camera can move. - */ - @JmeThread - protected boolean needMovableCamera() { - return true; - } - - /** - * Handle action events. - * - * @param name the name - * @param isPressed the is pressed - * @param tpf the tpf - */ - @JmeThread - protected void onActionImpl(final String name, final boolean isPressed, final float tpf) { - - final BooleanFloatConsumer handler = actionHandlers.get(name); - if (handler != null) { - handler.accept(isPressed, tpf); - } - - final EditorCamera editorCamera = getEditorCamera(); - - if (editorCamera != null && needMovableCamera()) { - editorCamera.setLockRotation(isShiftDown() && isButtonMiddleDown()); - } - } - - /** - * Rotate to. - * - * @param perspective the perspective - * @param isPressed the is pressed - */ - @JmeThread - protected void rotateTo(@NotNull final EditorCamera.Perspective perspective, final boolean isPressed) { - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera != null && isPressed) { - editorCamera.rotateTo(perspective); - } - } - - /** - * Rotate to. - * - * @param direction the direction - * @param isPressed the is pressed - */ - @JmeThread - protected void rotateTo(@NotNull final EditorCamera.Direction direction, final boolean isPressed) { - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera != null && isPressed) { - editorCamera.rotateTo(direction, 10F); - } - } - - /** - * Redo last operation. - */ - @JmeThread - protected void redo() { - } - - /** - * Undo last operation. - */ - @JmeThread - protected void undo() { - } - - /** - * Is alt down boolean. - * - * @return true if alt is pressed. - */ - @JmeThread - protected boolean isAltDown() { - return altDown; - } - - /** - * Sets alt down. - * - * @param altDown the alt is pressed. - */ - @JmeThread - protected void setAltDown(final boolean altDown) { - this.altDown = altDown; - } - - /** - * Is control down boolean. - * - * @return true if control is pressed. - */ - @JmeThread - protected boolean isControlDown() { - return controlDown; - } - - /** - * Sets control down. - * - * @param controlDown the control is pressed. - */ - @JmeThread - protected void setControlDown(final boolean controlDown) { - this.controlDown = controlDown; - } - - /** - * Is shift down boolean. - * - * @return true if shift is pressed. - */ - @JmeThread - protected boolean isShiftDown() { - return shiftDown; - } - - /** - * Sets shift down. - * - * @param shiftDown the shift is pressed. - */ - @JmeThread - protected void setShiftDown(final boolean shiftDown) { - this.shiftDown = shiftDown; - } - - /** - * Sets button left down. - * - * @param buttonLeftDown the left button is pressed. - */ - @JmeThread - protected void setButtonLeftDown(final boolean buttonLeftDown) { - this.buttonLeftDown = buttonLeftDown; - } - - /** - * Sets button middle down. - * - * @param buttonMiddleDown the middle button is pressed. - */ - @JmeThread - protected void setButtonMiddleDown(final boolean buttonMiddleDown) { - this.buttonMiddleDown = buttonMiddleDown; - } - - /** - * Sets button right down. - * - * @param buttonRightDown the right button is pressed. - */ - @JmeThread - protected void setButtonRightDown(final boolean buttonRightDown) { - this.buttonRightDown = buttonRightDown; - } - - /** - * Is button left down boolean. - * - * @return true if left button is pressed. - */ - @JmeThread - protected boolean isButtonLeftDown() { - return buttonLeftDown; - } - - /** - * Is button middle down boolean. - * - * @return true if middle button is pressed. - */ - @JmeThread - protected boolean isButtonMiddleDown() { - return buttonMiddleDown; - } - - /** - * Is button right down boolean. - * - * @return true if right button is pressed. - */ - @JmeThread - protected boolean isButtonRightDown() { - return buttonRightDown; - } - - /** - * Gets editor camera. - * - * @return the editor camera. - */ - @JmeThread - protected @Nullable EditorCamera getEditorCamera() { - return editorCamera; - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - this.stateManager = stateManager; - - final Node rootNode = EditorUtil.getGlobalRootNode(); - rootNode.attachChild(getStateNode()); - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.enableFilters(); - - final EditorCamera editorCamera = getEditorCamera(); - final InputManager inputManager = EditorUtil.getInputManager(); - - checkAndAddMappings(inputManager); - registerActionListener(inputManager); - registerAnalogListener(inputManager); - - if (editorCamera != null) { - editorCamera.setEnabled(true); - editorCamera.registerInput(inputManager); - } - } - - /** - * Check and update all triggers. - * - * @param inputManager the input manager - */ - @JmeThread - protected void checkAndAddMappings(@NotNull final InputManager inputManager) { - TRIGGERS.forEach(inputManager, AdvancedAbstractEditor3DPart::addMapping); - MULTI_TRIGGERS.forEach(inputManager, AdvancedAbstractEditor3DPart::addMapping); - } - - @JmeThread - private static void addMapping(@NotNull final InputManager inputManager, @NotNull final String name, - @NotNull final Trigger[] triggers) { - if (!inputManager.hasMapping(name)) inputManager.addMapping(name, triggers); - } - - @JmeThread - private static void addMapping(@NotNull final InputManager inputManager, @NotNull final String name, - @NotNull final Trigger trigger) { - if (!inputManager.hasMapping(name)) inputManager.addMapping(name, trigger); - } - - /** - * Register the analog listener. - * - * @param inputManager the input manager - */ - @JmeThread - protected void registerAnalogListener(@NotNull final InputManager inputManager) { - inputManager.addListener(analogListener, MOUSE_X_AXIS, MOUSE_X_AXIS_NEGATIVE, MOUSE_Y_AXIS, - MOUSE_Y_AXIS_NEGATIVE, MOUSE_MOVE_CAMERA_X_AXIS, MOUSE_MOVE_CAMERA_X_AXIS_NEGATIVE, - MOUSE_MOVE_CAMERA_Y_AXIS, MOUSE_MOVE_CAMERA_Y_AXIS_NEGATIVE); - } - - /** - * Register the action listener. - * - * @param inputManager the input manager - */ - @JmeThread - protected void registerActionListener(@NotNull final InputManager inputManager) { - inputManager.addListener(actionListener, MOUSE_RIGHT_CLICK, MOUSE_LEFT_CLICK, MOUSE_MIDDLE_CLICK); - inputManager.addListener(actionListener, KEY_CTRL, KEY_SHIFT, KEY_ALT, KEY_CTRL_S, KEY_CTRL_Z, KEY_CTRL_Y, KEY_NUM_1, - KEY_NUM_2, KEY_NUM_3, KEY_NUM_4, KEY_NUM_5, KEY_NUM_6, KEY_NUM_7, KEY_NUM_8, KEY_NUM_9, KEY_FLY_CAMERA_W, - KEY_FLY_CAMERA_S, KEY_FLY_CAMERA_A, KEY_FLY_CAMERA_D); - } - - @Override - @JmeThread - public void cleanup() { - super.cleanup(); - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.disableFilters(); - - final Node rootNode = EditorUtil.getGlobalRootNode(); - rootNode.detachChild(getStateNode()); - - final EditorCamera editorCamera = getEditorCamera(); - final InputManager inputManager = EditorUtil.getInputManager(); - inputManager.removeListener(actionListener); - inputManager.removeListener(analogListener); - - if (editorCamera != null) { - editorCamera.setEnabled(false); - editorCamera.unregisterInput(inputManager); - } - } - - /** - * Need editor camera boolean. - * - * @return true if need an editor camera. - */ - @JmeThread - protected boolean needEditorCamera() { - return false; - } - - /** - * Need light for camera boolean. - * - * @return true if need a camera light. - */ - @JmeThread - protected boolean needLightForCamera() { - return false; - } - - /** - * Create an editor camera. - * - * @return the new camera. - */ - @JmeThread - protected @NotNull EditorCamera createEditorCamera() { - - final Camera camera = EditorUtil.getGlobalCamera(); - final EditorCamera editorCamera = new EditorCamera(camera, getNodeForCamera()); - editorCamera.setMaxDistance(10000); - editorCamera.setMinDistance(0.01F); - editorCamera.setSmoothMotion(false); - editorCamera.setRotationSensitivity(1); - editorCamera.setZoomSensitivity(0.2F); - - return editorCamera; - } - - /** - * Create light for camera directional light. - * - * @return the light for the camera. - */ - @JmeThread - protected @NotNull DirectionalLight createLightForCamera() { - final DirectionalLight directionalLight = new DirectionalLight(); - directionalLight.setColor(ColorRGBA.White); - return directionalLight; - } - - /** - * Gets node for camera. - * - * @return the node for the camera. - */ - @JmeThread - protected @NotNull Node getNodeForCamera() { - return getStateNode(); - } - - /** - * Gets light for camera. - * - * @return the light for the camera. - */ - @JmeThread - protected @Nullable DirectionalLight getLightForCamera() { - return lightForCamera; - } - - /** - * Gets prev h rotation. - * - * @return the previous horizontal camera rotation. - */ - @JmeThread - protected float getPrevHRotation() { - return prevHRotation; - } - - /** - * Sets prev h rotation. - * - * @param prevHRotation the previous horizontal camera rotation. - */ - @JmeThread - protected void setPrevHRotation(final float prevHRotation) { - this.prevHRotation = prevHRotation; - } - - /** - * Gets prev target distance. - * - * @return the previous camera zoom. - */ - @JmeThread - protected float getPrevTargetDistance() { - return prevTargetDistance; - } - - /** - * Sets prev target distance. - * - * @param prevTargetDistance the previous camera zoom. - */ - @JmeThread - protected void setPrevTargetDistance(final float prevTargetDistance) { - this.prevTargetDistance = prevTargetDistance; - } - - /** - * Gets prev v rotation. - * - * @return the previous vertical camera rotation. - */ - @JmeThread - protected float getPrevVRotation() { - return prevVRotation; - } - - /** - * Sets prev v rotation. - * - * @param prevVRotation the previous vertical camera rotation. - */ - @JmeThread - protected void setPrevVRotation(final float prevVRotation) { - this.prevVRotation = prevVRotation; - } - - /** - * Gets prev camera location. - * - * @return the prev camera location - */ - @FromAnyThread - public @NotNull Vector3f getPrevCameraLocation() { - return prevCameraLocation; - } - - /** - * @return the camera speed. - */ - @FromAnyThread - private float getCameraSpeed() { - return cameraSpeed; - } - - /** - * @param cameraSpeed the camera speed. - */ - @FromAnyThread - private void setCameraSpeed(final float cameraSpeed) { - this.cameraSpeed = cameraSpeed; - } - - /** - * @return the prev camera speed. - */ - @FromAnyThread - private float getPrevCameraSpeed() { - return prevCameraSpeed; - } - - /** - * @param prevCameraSpeed the prev camera speed. - */ - @FromAnyThread - private void setPrevCameraSpeed(final float prevCameraSpeed) { - this.prevCameraSpeed = prevCameraSpeed; - } - - @Override - @JmeThread - public void update(float tpf) { - super.update(tpf); - preCameraUpdate(tpf); - cameraUpdate(tpf); - postCameraUpdate(tpf); - } - - @JmeThread - protected void postCameraUpdate(final float tpf) { - - final DirectionalLight lightForCamera = getLightForCamera(); - final EditorCamera editorCamera = getEditorCamera(); - - if (editorCamera != null && lightForCamera != null && needUpdateCameraLight()) { - final Camera camera = EditorUtil.getGlobalCamera(); - lightForCamera.setDirection(camera.getDirection().normalize()); - } - } - - @JmeThread - protected void cameraUpdate(final float tpf) { - - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera == null) { - return; - } - - editorCamera.updateCamera(tpf); - - final boolean[] cameraKeysState = getCameraKeysState(); - - if (isCameraMoving()) { - if (cameraKeysState[0]) { - moveSideCamera(tpf * 30, false, false, 0); - } - if (cameraKeysState[1]) { - moveSideCamera(-tpf * 30, false, false, 1); - } - if (cameraKeysState[2]) { - moveDirectionCamera(tpf * 30, false, false, 2); - } - if (cameraKeysState[3]) { - moveDirectionCamera(-tpf * 30, false, false, 3); - } - } - - checkCameraChanges(editorCamera); - } - - @JmeThread - protected void preCameraUpdate(final float tpf) { - } - - /** - * Check camera changes. - * - * @param editorCamera the editor camera - */ - @JmeThread - protected void checkCameraChanges(@NotNull final EditorCamera editorCamera) { - - int changes = 0; - - final Node nodeForCamera = getNodeForCamera(); - final Vector3f prevCameraLocation = getPrevCameraLocation(); - final Vector3f cameraLocation = nodeForCamera.getLocalTranslation(); - - final float prevHRotation = getPrevHRotation(); - final float hRotation = editorCamera.getHorizontalRotation(); - - final float prevVRotation = getPrevVRotation(); - final float vRotation = editorCamera.getVerticalRotation(); - - final float prevTargetDistance = getPrevTargetDistance(); - final float targetDistance = editorCamera.getTargetDistance(); - - final float cameraSpeed = getCameraSpeed(); - final float prevCameraSpeed = getPrevCameraSpeed(); - - if (!prevCameraLocation.equals(cameraLocation)) { - changes++; - } else if (prevHRotation != hRotation || prevVRotation != vRotation) { - changes++; - } else if (prevTargetDistance != targetDistance) { - changes++; - } else if (cameraSpeed != prevCameraSpeed) { - changes++; - } - - if (changes > 0) { - notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed); - } - - prevCameraLocation.set(cameraLocation); - - setPrevHRotation(hRotation); - setPrevVRotation(vRotation); - setPrevTargetDistance(targetDistance); - setPrevCameraSpeed(cameraSpeed); - } - - /** - * Notify about changed camera's settings. - * - * @param cameraLocation the camera location. - * @param hRotation the h rotation. - * @param vRotation the v rotation. - * @param targetDistance the target distance. - * @param cameraSpeed the camera speed. - */ - @JmeThread - protected void notifyChangedCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, - final float cameraSpeed) { - } - - /** - * Update the editor camera settings. - * - * @param cameraLocation the camera location. - * @param hRotation the h rotation. - * @param vRotation the v rotation. - * @param targetDistance the target distance. - * @param cameraSpeed the camera speed. - */ - @JmeThread - public void updateCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, final float cameraSpeed) { - - final EditorCamera editorCamera = getEditorCamera(); - if (editorCamera == null) return; - - editorCamera.setTargetRotation(hRotation); - editorCamera.setTargetVRotation(vRotation); - editorCamera.setTargetDistance(targetDistance); - - getNodeForCamera().setLocalTranslation(cameraLocation); - getPrevCameraLocation().set(cameraLocation); - - setPrevHRotation(hRotation); - setPrevVRotation(vRotation); - setPrevTargetDistance(targetDistance); - setPrevCameraSpeed(cameraSpeed); - setCameraSpeed(cameraSpeed); - - editorCamera.update(1F); - } - - /** - * Need update camera light boolean. - * - * @return true if need to update the camera light. - */ - @JmeThread - protected boolean needUpdateCameraLight() { - return false; - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/Stats3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/Stats3DPart.java deleted file mode 100644 index 24e4e427..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/Stats3DPart.java +++ /dev/null @@ -1,541 +0,0 @@ -package com.ss.editor.part3d.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.app.Application; -import com.jme3.app.state.AbstractAppState; -import com.jme3.app.state.AppStateManager; -import com.jme3.renderer.Statistics; -import com.jme3.system.Timer; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.part3d.editor.Editor3DPart; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.ArrayUtils; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Pane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * The 3D state to get and to show statistics of rendering. - * - * @author JavaSaBr - */ -public class Stats3DPart extends AbstractAppState implements Editor3DPart { - - @NotNull - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - @NotNull - private static final AtomicInteger STATISTICS_ENABLED = new AtomicInteger(0); - - /** - * The parent node. - */ - @NotNull - private final Pane parent; - - /** - * The stats parent. - */ - @NotNull - private final GridPane statsContainer; - - /** - * The frame buffer M field. - */ - @Nullable - private Label frameBuffersMField; - - /** - * The frame buffer F field. - */ - @Nullable - private Label frameBuffersFField; - - /** - * The frame buffer S field. - */ - @Nullable - private Label frameBuffersSField; - - /** - * The textures M field. - */ - @Nullable - private Label texturesMField; - - /** - * The textures F field. - */ - @Nullable - private Label texturesFField; - - /** - * The textures S field. - */ - @Nullable - private Label texturesSField; - - /** - * The shaders M field. - */ - @Nullable - private Label shadersMField; - - /** - * The shaders F field. - */ - @Nullable - private Label shadersFField; - - /** - * The shaders S field. - */ - @Nullable - private Label shadersSField; - - /** - * The objects field. - */ - @Nullable - private Label objectsField; - - /** - * The uniforms field. - */ - @Nullable - private Label uniformsField; - - /** - * The triangles field. - */ - @Nullable - private Label trianglesField; - - /** - * The vertices S field. - */ - @Nullable - private Label verticesField; - - /** - * The filed to show FPS. - */ - @Nullable - private Label fpsField; - - /** - * The current application. - */ - @Nullable - private Application application; - - /** - * The statistics. - */ - @Nullable - private Statistics statistics; - - /** - * The container of stats data. - */ - @Nullable - private int[] statsData; - - /** - * The container of prev stats data. - */ - @Nullable - private int[] prevStatsData; - - private float secondCounter; - private int frameCounter; - - private int fps; - private int prevFps; - - public Stats3DPart(@NotNull final Pane parent) { - this.parent = parent; - this.statsContainer = new GridPane(); - this.frameCounter = 0; - this.secondCounter = 0.0f; - this.prevFps = -1; - createComponents(); - setEnabled(false); - } - - /** - * Create stats fields. - */ - @FxThread - private void createComponents() { - - final Label frameBuffersMLabel = new Label("FrameBuffers (M)"); - frameBuffersMField = new Label(); - - final Label frameBuffersFLabel = new Label("FrameBuffers (F)"); - frameBuffersFField = new Label(); - - final Label frameBuffersSLabel = new Label("FrameBuffers (S)"); - frameBuffersSField = new Label(); - - final Label texturesMLabel = new Label("Textures (M)"); - texturesMField = new Label(); - - final Label texturesFLabel = new Label("Textures (F)"); - texturesFField = new Label(); - - final Label texturesSLabel = new Label("Textures (S)"); - texturesSField = new Label(); - - final Label shadersMLabel = new Label("Shaders (M)"); - shadersMField = new Label(); - - final Label shadersFLabel = new Label("Shaders (F)"); - shadersFField = new Label(); - - final Label shadersSLabel = new Label("Shaders (S)"); - shadersSField = new Label(); - - final Label objectsLabel = new Label("Objects"); - objectsField = new Label(); - - final Label uniformsLabel = new Label("Uniforms"); - uniformsField = new Label(); - - final Label trianglesLabel = new Label("Triangles"); - trianglesField = new Label(); - - final Label verticesLabel = new Label("Vertices"); - verticesField = new Label(); - - final Label fpsLabel = new Label("Fps"); - fpsField = new Label(); - - statsContainer.add(frameBuffersMLabel, 0, 0); - statsContainer.add(frameBuffersMField, 1, 0); - statsContainer.add(frameBuffersFLabel, 0, 1); - statsContainer.add(frameBuffersFField, 1, 1); - statsContainer.add(frameBuffersSLabel, 0, 2); - statsContainer.add(frameBuffersSField, 1, 2); - statsContainer.add(texturesMLabel, 0, 3); - statsContainer.add(texturesMField, 1, 3); - statsContainer.add(texturesFLabel, 0, 4); - statsContainer.add(texturesFField, 1, 4); - statsContainer.add(texturesSLabel, 0, 5); - statsContainer.add(texturesSField, 1, 5); - statsContainer.add(shadersMLabel, 0, 6); - statsContainer.add(shadersMField, 1, 6); - statsContainer.add(shadersFLabel, 0, 7); - statsContainer.add(shadersFField, 1, 7); - statsContainer.add(shadersSLabel, 0, 8); - statsContainer.add(shadersSField, 1, 8); - statsContainer.add(objectsLabel, 0, 9); - statsContainer.add(objectsField, 1, 9); - statsContainer.add(uniformsLabel, 0, 10); - statsContainer.add(uniformsField, 1, 10); - statsContainer.add(trianglesLabel, 0, 11); - statsContainer.add(trianglesField, 1, 11); - statsContainer.add(verticesLabel, 0, 12); - statsContainer.add(verticesField, 1, 12); - statsContainer.add(fpsLabel, 0, 13); - statsContainer.add(fpsField, 1, 13); - - FXUtils.addClassTo(statsContainer, CssClasses.STATS_3D_STATE); - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - this.application = application; - this.statistics = application.getRenderer().getStatistics(); - this.statsData = new int[statistics.getLabels().length]; - this.prevStatsData = new int[statistics.getLabels().length]; - - statistics.setEnabled(STATISTICS_ENABLED.incrementAndGet() > 0); - - EXECUTOR_MANAGER.addFxTask(() -> FXUtils.addToPane(statsContainer, parent)); - } - - @Override - @JmeThread - public void setEnabled(final boolean enabled) { - super.setEnabled(enabled); - EXECUTOR_MANAGER.addFxTask(() -> statsContainer.setVisible(enabled)); - } - - /** - * Get the current application. - * - * @return the current application. - */ - @FromAnyThread - private @NotNull Application getApplication() { - return notNull(application); - } - - /** - * Get the statistics. - * - * @return the statistics. - */ - @FromAnyThread - private @NotNull Statistics getStatistics() { - return notNull(statistics); - } - - /** - * Get the container of stats data. - * - * @return the container of stats data. - */ - @FromAnyThread - private @NotNull int[] getStatsData() { - return notNull(statsData); - } - - /** - * Get the container of prev stats data. - * - * @return the container of prev stats data. - */ - @FromAnyThread - private @Nullable int[] getPrevStatsData() { - return prevStatsData; - } - - /** - * Get the filed to show FPS. - * - * @return the filed to show FPS. - */ - @FxThread - private @NotNull Label getFpsField() { - return notNull(fpsField); - } - - /** - * Get the vertices S field. - * - * @return the vertices S field. - */ - @FxThread - private @NotNull Label getVerticesField() { - return notNull(verticesField); - } - - /** - * Get the triangles field. - * - * @return the triangles field. - */ - @FxThread - private @NotNull Label getTrianglesField() { - return notNull(trianglesField); - } - - /** - * Get the uniforms field. - * - * @return the uniforms field. - */ - @FxThread - private @NotNull Label getUniformsField() { - return notNull(uniformsField); - } - - /** - * Get the objects field. - * - * @return the objects field. - */ - @FxThread - private @NotNull Label getObjectsField() { - return notNull(objectsField); - } - - /** - * Get the shaders F field. - * - * @return the shaders F field. - */ - @FxThread - private @NotNull Label getShadersFField() { - return notNull(shadersFField); - } - - /** - * Get the shaders M field. - * - * @return the shaders M field. - */ - @FxThread - private @NotNull Label getShadersMField() { - return notNull(shadersMField); - } - - /** - * Get the shaders S field. - * - * @return the shaders S field. - */ - @FxThread - private @NotNull Label getShadersSField() { - return notNull(shadersSField); - } - - /** - * Get the textures F field. - * - * @return the textures F field. - */ - @FxThread - private @NotNull Label getTexturesFField() { - return notNull(texturesFField); - } - - /** - * Get the textures M field. - * - * @return the textures M field. - */ - @FxThread - private @NotNull Label getTexturesMField() { - return notNull(texturesMField); - } - - /** - * Get the textures S field. - * - * @return the textures S field. - */ - @FxThread - private @NotNull Label getTexturesSField() { - return notNull(texturesSField); - } - - /** - * Get the frame buffer F field. - * - * @return the frame buffer F field. - */ - @FxThread - private @NotNull Label getFrameBuffersFField() { - return notNull(frameBuffersFField); - } - - /** - * Get the frame buffer M field. - * - * @return the frame buffer M field. - */ - @FxThread - private @NotNull Label getFrameBuffersMField() { - return notNull(frameBuffersMField); - } - - /** - * Get the frame buffer S field. - * - * @return the frame buffer S field. - */ - @FxThread - private @NotNull Label getFrameBuffersSField() { - return notNull(frameBuffersSField); - } - - @Override - @JmeThread - public void update(final float tpf) { - if (!isEnabled()) { - return; - } - - final Application application = getApplication(); - final Timer timer = application.getTimer(); - - secondCounter += timer.getTimePerFrame(); - frameCounter++; - - if (secondCounter >= 1.0f) { - fps = (int) (frameCounter / secondCounter); - if (fps != prevFps) { - secondCounter = 0.0f; - frameCounter = 0; - updateFps(fps); - prevFps = fps; - } - } - - final int[] statsData = getStatsData(); - - final Statistics statistics = getStatistics(); - statistics.getData(statsData); - - final int[] prevStatsData = getPrevStatsData(); - - if (Arrays.equals(statsData, prevStatsData)) { - return; - } - - ArrayUtils.copyTo(statsData, prevStatsData); - - final int vertices = statsData[0]; - final int triangles = statsData[1]; - final int uniforms = statsData[2]; - final int objects = statsData[3]; - final int shadersS = statsData[4]; - final int shadersF = statsData[5]; - final int shadersM = statsData[6]; - final int texturesS = statsData[7]; - final int texturesF = statsData[8]; - final int texturesM = statsData[9]; - final int frameBuffersS = statsData[10]; - final int frameBuffersF = statsData[11]; - final int frameBuffersM = statsData[12]; - - EXECUTOR_MANAGER.addFxTask(() -> { - getVerticesField().setText(Integer.toString(vertices)); - getTrianglesField().setText(Integer.toString(triangles)); - getUniformsField().setText(Integer.toString(uniforms)); - getObjectsField().setText(Integer.toString(objects)); - getShadersSField().setText(Integer.toString(shadersS)); - getShadersFField().setText(Integer.toString(shadersF)); - getShadersMField().setText(Integer.toString(shadersM)); - getTexturesSField().setText(Integer.toString(texturesS)); - getTexturesFField().setText(Integer.toString(texturesF)); - getTexturesMField().setText(Integer.toString(texturesM)); - getFrameBuffersSField().setText(Integer.toString(frameBuffersS)); - getFrameBuffersFField().setText(Integer.toString(frameBuffersF)); - getFrameBuffersMField().setText(Integer.toString(frameBuffersM)); - }); - } - - /** - * Update the FPS value. - */ - @JmeThread - private void updateFps(final int fps) { - EXECUTOR_MANAGER.addFxTask(() -> getFpsField().setText(Integer.toString(fps))); - } - - @Override - @JmeThread - public void cleanup() { - super.cleanup(); - - final Statistics statistics = getStatistics(); - statistics.setEnabled(STATISTICS_ENABLED.decrementAndGet() == 0); - - EXECUTOR_MANAGER.addFxTask(() -> FXUtils.removeFromParent(statsContainer, parent)); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/audio/AudioViewer3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/audio/AudioViewer3DPart.java deleted file mode 100644 index 462475a1..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/audio/AudioViewer3DPart.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.ss.editor.part3d.editor.impl.audio; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioNode; -import com.jme3.audio.AudioSource.Status; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.part3d.editor.impl.AbstractEditor3DPart; -import com.ss.editor.ui.component.editor.impl.AudioViewerEditor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of an editor app state for the {@link AudioViewerEditor}. - * - * @author JavaSaBr - */ -public class AudioViewer3DPart extends AbstractEditor3DPart { - - /** - * The previous status. - */ - @Nullable - private volatile Status prevStatus; - - /** - * The audio node. - */ - @Nullable - private AudioNode audioNode; - - /** - * The audio data. - */ - @Nullable - private AudioData audioData; - - /** - * The audio key. - */ - @Nullable - private AudioKey audioKey; - - public AudioViewer3DPart(@NotNull final AudioViewerEditor fileEditor) { - super(fileEditor); - } - - /** - * Load the audio data. - * - * @param audioData the audio data. - * @param audioKey the audio key. - */ - @FromAnyThread - public void load(@NotNull final AudioData audioData, @NotNull final AudioKey audioKey) { - EXECUTOR_MANAGER.addJmeTask(() -> loadImpl(audioData, audioKey)); - } - - /** - * Load the audio data. - * - * @param audioData the audio data. - * @param audioKey the audio key. - */ - @JmeThread - private void loadImpl(@NotNull final AudioData audioData, @NotNull final AudioKey audioKey) { - removeAudioNode(); - setAudioData(audioData); - setAudioKey(audioKey); - - final Node stateNode = getStateNode(); - - final AudioNode audioNode = new AudioNode(audioData, audioKey); - audioNode.setPositional(false); - stateNode.attachChild(audioNode); - - setAudioNode(audioNode); - } - - /** - * Remove the current audio node. - */ - @JmeThread - private void removeAudioNode() { - - final AudioNode currentAudioNode = getAudioNode(); - if (currentAudioNode == null) { - return; - } - - final Node stateNode = getStateNode(); - final Status status = currentAudioNode.getStatus(); - - if (status == Status.Playing || status == Status.Paused) { - currentAudioNode.stop(); - } - - stateNode.detachChild(currentAudioNode); - - setAudioNode(null); - setPrevStatus(null); - } - - /** - * Play the current audio. - */ - @FromAnyThread - public void play() { - EXECUTOR_MANAGER.addJmeTask(this::playImpl); - } - - /** - * Play the current audio. - */ - @JmeThread - private void playImpl() { - - final AudioNode currentAudioNode = getAudioNode(); - - if (currentAudioNode != null) { - - final Status status = currentAudioNode.getStatus(); - - if (status == Status.Paused) { - currentAudioNode.play(); - return; - } else if (status == Status.Playing) { - return; - } - } - - loadImpl(getAudioData(), getAudioKey()); - - final AudioNode audioNode = getAudioNode(); - audioNode.play(); - } - - @Override - @JmeThread - public void cleanup() { - stopImpl(); - super.cleanup(); - } - - /** - * Pause the current audio. - */ - @FromAnyThread - public void pause() { - EXECUTOR_MANAGER.addJmeTask(this::pauseImpl); - } - - /** - * Pause the current audio. - */ - @JmeThread - private void pauseImpl() { - final AudioNode currentAudioNode = getAudioNode(); - if (currentAudioNode == null) return; - currentAudioNode.pause(); - } - - /** - * Stop the current audio. - */ - @FromAnyThread - public void stop() { - EXECUTOR_MANAGER.addJmeTask(this::stopImpl); - } - - /** - * Stop the current audio. - */ - @JmeThread - private void stopImpl() { - removeAudioNode(); - EXECUTOR_MANAGER.addFxTask(() -> getFileEditor().notifyChangedStatus(Status.Stopped)); - } - - @Override - @JmeThread - public void update(final float tpf) { - super.update(tpf); - - final AudioNode audioNode = getAudioNode(); - if (audioNode == null) return; - - final Status status = audioNode.getStatus(); - if (status != getPrevStatus()) { - EXECUTOR_MANAGER.addFxTask(() -> getFileEditor().notifyChangedStatus(status)); - setPrevStatus(status); - } - } - - /** - * Get the audio node. - * - * @return the audio node. - */ - @JmeThread - private @Nullable AudioNode getAudioNode() { - return audioNode; - } - - /** - * Set the audio node. - * - * @param audioNode the audio node. - */ - @JmeThread - private void setAudioNode(@Nullable final AudioNode audioNode) { - this.audioNode = audioNode; - } - - /** - * Get the audio data. - * - * @return the audio data. - */ - @JmeThread - private @NotNull AudioData getAudioData() { - return notNull(audioData); - } - - /** - * Set the audio data. - * - * @param audioData the audio data. - */ - @JmeThread - private void setAudioData(@NotNull final AudioData audioData) { - this.audioData = audioData; - } - - /** - * Get the audio key. - * - * @return the audio key. - */ - @JmeThread - private @NotNull AudioKey getAudioKey() { - return notNull(audioKey); - } - - /** - * Set the audio key. - * - * @param audioKey the audio key. - */ - @JmeThread - private void setAudioKey(@NotNull final AudioKey audioKey) { - this.audioKey = audioKey; - } - - /** - * Get previous prev status. - * - * @return the previous status. - */ - @FromAnyThread - public @Nullable Status getPrevStatus() { - return prevStatus; - } - - /** - * Set previous prev status. - * - * @param prevStatus the previous status. - */ - @JmeThread - private void setPrevStatus(@Nullable final Status prevStatus) { - this.prevStatus = prevStatus; - } - - @Override - public String toString() { - return "AudioViewer3DState{" + - "prevStatus=" + prevStatus + - ", audioNode=" + audioNode + - ", audioData=" + audioData + - ", audioKey=" + audioKey + - "} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/material/MaterialEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/material/MaterialEditor3DPart.java deleted file mode 100644 index 575dc861..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/material/MaterialEditor3DPart.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ss.editor.part3d.editor.impl.material; - -import com.ss.editor.plugin.api.editor.material.BaseMaterialEditor3DPart; -import com.ss.editor.ui.component.editor.impl.material.MaterialFileEditor; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation the 3D part of the {@link MaterialFileEditor} but it can be reused in other cases. - * - * @author JavaSaBr - */ -public class MaterialEditor3DPart extends BaseMaterialEditor3DPart { - - public MaterialEditor3DPart(@NotNull final MaterialFileEditor fileEditor) { - super(fileEditor); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditor3DPart.java deleted file mode 100644 index 09abef91..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditor3DPart.java +++ /dev/null @@ -1,312 +0,0 @@ -package com.ss.editor.part3d.editor.impl.model; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.environment.generation.JobProgressAdapter; -import com.jme3.light.DirectionalLight; -import com.jme3.light.LightProbe; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart; -import com.ss.editor.plugin.api.RenderFilterExtension; -import com.ss.editor.ui.component.editor.impl.model.ModelFileEditor; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link AbstractSceneEditor3DPart} for the {@link ModelFileEditor}. - * - * @author JavaSaBr - */ -public class ModelEditor3DPart extends AbstractSceneEditor3DPart { - - @NotNull - private final JobProgressAdapter probeHandler = new JobProgressAdapter() { - - @Override - public void done(final LightProbe result) { - if (!isInitialized()) return; - notifyProbeComplete(); - } - }; - - /** - * The array of custom skies. - */ - @NotNull - private final Array customSky; - - /** - * The node for the placement of custom sky. - */ - @NotNull - private final Node customSkyNode; - - /** - * The current fast sky. - */ - @Nullable - private Spatial currentFastSky; - - /** - * The flag of activity light of the camera. - */ - private boolean lightEnabled; - - /** - * The frame rate. - */ - private int frame; - - public ModelEditor3DPart(@NotNull final ModelFileEditor fileEditor) { - super(fileEditor); - this.customSkyNode = new Node("Custom Sky"); - this.customSky = ArrayFactory.newArray(Spatial.class); - - final Node stateNode = getStateNode(); - stateNode.attachChild(getCustomSkyNode()); - - setLightEnabled(true); - } - - /** - * @return the node for the placement of custom sky. - */ - @JmeThread - private @NotNull Node getCustomSkyNode() { - return customSkyNode; - } - - /** - * @return the array of custom skies. - */ - @JmeThread - private @NotNull Array getCustomSky() { - return customSky; - } - - /** - * Activate the node with models. - */ - @JmeThread - private void notifyProbeComplete() { - - final Node stateNode = getStateNode(); - stateNode.attachChild(getModelNode()); - stateNode.attachChild(getToolNode()); - - final Node customSkyNode = getCustomSkyNode(); - customSkyNode.detachAllChildren(); - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.refreshFilters(); - } - - /** - * @param currentFastSky the current fast sky. - */ - @JmeThread - private void setCurrentFastSky(@Nullable final Spatial currentFastSky) { - this.currentFastSky = currentFastSky; - } - - /** - * @return the current fast sky. - */ - @JmeThread - private @Nullable Spatial getCurrentFastSky() { - return currentFastSky; - } - - /** - * @return true if the light of the camera is enabled. - */ - @JmeThread - private boolean isLightEnabled() { - return lightEnabled; - } - - /** - * @param lightEnabled the flag of activity light of the camera. - */ - @JmeThread - private void setLightEnabled(final boolean lightEnabled) { - this.lightEnabled = lightEnabled; - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - frame = 0; - } - - @Override - @JmeThread - public void cleanup() { - super.cleanup(); - - final Node stateNode = getStateNode(); - stateNode.detachChild(getModelNode()); - stateNode.detachChild(getToolNode()); - } - - @Override - @JmeThread - public void update(final float tpf) { - super.update(tpf); - - if (frame == 2) { - final Node customSkyNode = getCustomSkyNode(); - final Array customSky = getCustomSky(); - customSky.forEach(spatial -> customSkyNode.attachChild(spatial.clone(false))); - EditorUtil.updateGlobalLightProbe(probeHandler); - } - - frame++; - } - - @Override - @JmeThread - protected boolean needUpdateCameraLight() { - return true; - } - - @Override - @JmeThread - protected boolean needLightForCamera() { - return true; - } - - /** - * Update light. - * - * @param enabled the enabled - */ - @FromAnyThread - public void updateLightEnabled(final boolean enabled) { - EXECUTOR_MANAGER.addJmeTask(() -> updateLightEnabledImpl(enabled)); - } - - /** - * The process of updating the light. - */ - @JmeThread - private void updateLightEnabledImpl(boolean enabled) { - - if (enabled == isLightEnabled()) { - return; - } - - final DirectionalLight light = getLightForCamera(); - final Node stateNode = getStateNode(); - - if (enabled) { - stateNode.addLight(light); - } else { - stateNode.removeLight(light); - } - - setLightEnabled(enabled); - } - - /** - * Change the fast sky. - * - * @param fastSky the fast sky - */ - @FromAnyThread - public void changeFastSky(@Nullable final Spatial fastSky) { - EXECUTOR_MANAGER.addJmeTask(() -> changeFastSkyImpl(fastSky)); - } - - /** - * The process of changing the fast sky. - */ - @JmeThread - private void changeFastSkyImpl(@Nullable final Spatial fastSky) { - - final Node stateNode = getStateNode(); - final Spatial currentFastSky = getCurrentFastSky(); - - if (currentFastSky != null) { - stateNode.detachChild(currentFastSky); - } - - if (fastSky != null) { - stateNode.attachChild(fastSky); - } - - stateNode.detachChild(getModelNode()); - stateNode.detachChild(getToolNode()); - - setCurrentFastSky(fastSky); - - frame = 0; - } - - /** - * Add the custom sky. - * - * @param sky the sky - */ - @FromAnyThread - public void addCustomSky(@NotNull final Spatial sky) { - EXECUTOR_MANAGER.addJmeTask(() -> addCustomSkyImpl(sky)); - } - - /** - * The process of adding the custom sky. - */ - @JmeThread - private void addCustomSkyImpl(@NotNull final Spatial sky) { - final Array customSky = getCustomSky(); - customSky.add(sky); - } - - /** - * Remove the custom sky. - * - * @param sky the sky - */ - @FromAnyThread - public void removeCustomSky(@NotNull final Spatial sky) { - EXECUTOR_MANAGER.addJmeTask(() -> removeCustomSkyImpl(sky)); - } - - /** - * The process of removing the custom sky. - */ - @JmeThread - private void removeCustomSkyImpl(@NotNull final Spatial sky) { - final Array customSky = getCustomSky(); - customSky.slowRemove(sky); - } - - /** - * Update the light probe. - */ - @FromAnyThread - public void updateLightProbe() { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final Node stateNode = getStateNode(); - stateNode.detachChild(getModelNode()); - stateNode.detachChild(getToolNode()); - - frame = 0; - }); - } - - @Override - public String toString() { - return "ModelEditor3DState{" + - ", lightEnabled=" + lightEnabled + - "} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditorBulletPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditorBulletPart.java deleted file mode 100644 index 335eabb4..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/model/ModelEditorBulletPart.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.part3d.editor.impl.model; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.control.PhysicsControl; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.extension.scene.app.state.impl.bullet.EditableBulletSceneAppState; -import com.ss.editor.part3d.editor.Editor3DPart; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of editor 3D state to work with Bullet physics. - * - * @author JavaSaBr - */ -public class ModelEditorBulletPart extends EditableBulletSceneAppState implements Editor3DPart { - - @NotNull - private final ModelEditor3DPart editor3DPart; - - public ModelEditorBulletPart(@NotNull final ModelEditor3DPart editor3DPart) { - this.editor3DPart = editor3DPart; - } - - @Override - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application app) { - super.initialize(stateManager, app); - - final Spatial currentModel = editor3DPart.getCurrentModel(); - if (currentModel != null) { - updateNode(currentModel, physicsSpace); - } - } - - @Override - protected void rebuildState() { - super.rebuildState(); - - if (!isInitialized()) { - return; - } - - final Spatial currentModel = editor3DPart.getCurrentModel(); - if (currentModel != null) { - updateNode(currentModel, physicsSpace); - } - } - - /** - * Update a spatial. - * - * @param spatial the spatial. - * @param physicsSpace the new physical space or null. - */ - @JmeThread - private void updateNode(@NotNull final Spatial spatial, @Nullable final PhysicsSpace physicsSpace) { - spatial.depthFirstTraversal(sub -> { - - final int numControls = sub.getNumControls(); - - for (int i = 0; i < numControls; i++) { - final Control control = sub.getControl(i); - if (control instanceof PhysicsControl) { - ((PhysicsControl) control).setPhysicsSpace(physicsSpace); - } - } - }); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java deleted file mode 100644 index 28865cf5..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java +++ /dev/null @@ -1,2410 +0,0 @@ -package com.ss.editor.part3d.editor.impl.scene; - -import static com.ss.editor.util.NodeUtils.findParent; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.app.state.AppState; -import com.jme3.asset.AssetManager; -import com.jme3.asset.AssetNotFoundException; -import com.jme3.audio.AudioNode; -import com.jme3.bounding.BoundingBox; -import com.jme3.bounding.BoundingSphere; -import com.jme3.bounding.BoundingVolume; -import com.jme3.collision.CollisionResult; -import com.jme3.collision.CollisionResults; -import com.jme3.effect.ParticleEmitter; -import com.jme3.input.InputManager; -import com.jme3.input.KeyInput; -import com.jme3.input.controls.KeyTrigger; -import com.jme3.light.Light; -import com.jme3.material.Material; -import com.jme3.material.RenderState; -import com.jme3.math.*; -import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.RendererException; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.*; -import com.jme3.scene.debug.Grid; -import com.jme3.scene.debug.WireBox; -import com.jme3.scene.debug.WireSphere; -import com.jme3.scene.shape.Box; -import com.jme3.scene.shape.Line; -import com.jme3.scene.shape.Quad; -import com.jme3.scene.shape.Sphere; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.painting.PaintingControl; -import com.ss.editor.control.painting.PaintingInput; -import com.ss.editor.control.transform.*; -import com.ss.editor.extension.property.SimpleProperty; -import com.ss.editor.extension.scene.ScenePresentable; -import com.ss.editor.model.EditorCamera; -import com.ss.editor.model.scene.*; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.part3d.editor.impl.scene.handler.ApplyScaleToPhysicsControlsHandler; -import com.ss.editor.part3d.editor.impl.scene.handler.DisableControlsTransformationHandler; -import com.ss.editor.part3d.editor.impl.scene.handler.PhysicsControlTransformationHandler; -import com.ss.editor.part3d.editor.impl.scene.handler.ReactivatePhysicsControlsTransformationHandler; -import com.ss.editor.plugin.api.editor.part3d.Advanced3DEditorPart; -import com.ss.editor.ui.component.editor.impl.scene.AbstractSceneFileEditor; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.util.*; -import com.ss.rlib.common.function.BooleanFloatConsumer; -import com.ss.rlib.common.geom.util.AngleUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.array.ArrayIterator; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.scene.input.KeyCode; -import javafx.scene.input.MouseButton; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The base implementation of the {@link AppState} for the editor. - * - * @param the type of file scene editor. - * @param the type of edited spatial. - * @author JavaSaBr - */ -public abstract class AbstractSceneEditor3DPart - extends Advanced3DEditorPart implements EditorTransformSupport { - - public static final String KEY_LOADED_MODEL = "jMB.sceneEditor.loadedModel"; - public static final String KEY_IGNORE_RAY_CAST = "jMB.sceneEditor.ignoreRayCast"; - public static final String KEY_MODEL_NODE = "jMB.sceneEditor.modelNode"; - public static final String KEY_SHAPE_CENTER = "jMB.sceneEditor.shapeCenter"; - public static final String KEY_SHAPE_INIT_SCALE = "jMB.sceneEditor.initScale"; - - private static final String KEY_S = "SSEditor.sceneEditorState.S"; - private static final String KEY_G = "SSEditor.sceneEditorState.G"; - private static final String KEY_R = "SSEditor.sceneEditorState.R"; - private static final String KEY_DEL = "SSEditor.sceneEditorState.Del"; - - private static final float H_ROTATION = AngleUtils.degreeToRadians(45); - private static final float V_ROTATION = AngleUtils.degreeToRadians(15); - - static { - TRIGGERS.put(KEY_S, new KeyTrigger(KeyInput.KEY_S)); - TRIGGERS.put(KEY_G, new KeyTrigger(KeyInput.KEY_G)); - TRIGGERS.put(KEY_R, new KeyTrigger(KeyInput.KEY_R)); - TRIGGERS.put(KEY_DEL, new KeyTrigger(KeyInput.KEY_DELETE)); - } - - /** - * The table with models to present lights on a scene. - */ - @NotNull - private static final ObjectDictionary LIGHT_MODEL_TABLE; - - private static final Node AUDIO_NODE_MODEL; - - static { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - AUDIO_NODE_MODEL = (Node) assetManager.loadModel("graphics/models/speaker/speaker.j3o"); - - LIGHT_MODEL_TABLE = DictionaryFactory.newObjectDictionary(); - LIGHT_MODEL_TABLE.put(Light.Type.Point, (Node) assetManager.loadModel("graphics/models/light/point_light.j3o")); - LIGHT_MODEL_TABLE.put(Light.Type.Directional, (Node) assetManager.loadModel("graphics/models/light/direction_light.j3o")); - LIGHT_MODEL_TABLE.put(Light.Type.Spot, (Node) assetManager.loadModel("graphics/models/light/spot_light.j3o")); - } - - @NotNull - private static final Array> SELECTION_FINDERS = ArrayFactory.newArray(Function.class); - - @NotNull - private static final Array> PRE_TRANSFORM_HANDLERS = ArrayFactory.newArray(Consumer.class); - - @NotNull - private static final Array> POST_TRANSFORM_HANDLERS = ArrayFactory.newArray(Consumer.class); - - /** - * Register the additional selection object finder. - * - * @param finder the additional selection object finder. - */ - @JmeThread - public static void registerSelectionFinder(@NotNull final Function finder) { - SELECTION_FINDERS.add(finder); - } - - /** - * Register the pre transform handler. - * - * @param handler the pre transform handler. - */ - @JmeThread - public static void registerPreTransformHandler(@NotNull final Consumer handler) { - PRE_TRANSFORM_HANDLERS.add(handler); - } - - /** - * Register the post transform handler. - * - * @param handler the post transform handler. - */ - @JmeThread - public static void registerPostTransformHandler(@NotNull final Consumer handler) { - POST_TRANSFORM_HANDLERS.add(handler); - } - - static { - - // default handlers - final DisableControlsTransformationHandler disableControlsHandler = new DisableControlsTransformationHandler(); - final ApplyScaleToPhysicsControlsHandler applyScaleToPhysicsControlsHandler = new ApplyScaleToPhysicsControlsHandler(); - - registerPreTransformHandler(disableControlsHandler::onPreTransform); - registerPostTransformHandler(disableControlsHandler::onPostTransform); - registerPostTransformHandler(new ReactivatePhysicsControlsTransformationHandler()); - registerPostTransformHandler(new PhysicsControlTransformationHandler()); - registerPreTransformHandler(applyScaleToPhysicsControlsHandler::onPreTransform); - registerPostTransformHandler(applyScaleToPhysicsControlsHandler::onPostTransform); - } - - /** - * The map with cached light nodes. - */ - @NotNull - private final ObjectDictionary cachedLights; - - /** - * The map with cached audio nodes. - */ - @NotNull - private final ObjectDictionary cachedAudioNodes; - - /** - * The map with cached presentable objects. - */ - @NotNull - private final ObjectDictionary cachedPresentableObjects; - - /** - * The array of light nodes. - */ - @NotNull - private final Array lightNodes; - - /** - * The array of audio nodes. - */ - @NotNull - private final Array audioNodes; - - /** - * The array of scene presentable nodes. - */ - @NotNull - private final Array presentableNodes; - - /** - * The selection models of selected models. - */ - @NotNull - private final ObjectDictionary selectionShape; - - /** - * The array of selected models. - */ - @NotNull - protected final Array selected; - - /** - * The node for the placement of controls. - */ - @NotNull - private final Node toolNode; - - /** - * The node for the placement of transform controls. - */ - @NotNull - private final Node transformToolNode; - - /** - * The node for the placement of models. - */ - @NotNull - private final Node modelNode; - - /** - * The node for the placement of lights. - */ - @NotNull - private final Node lightNode; - - /** - * The node for the placement of audio nodes. - */ - @NotNull - private final Node audioNode; - - /** - * The node for the placement of presentable nodes. - */ - @NotNull - private final Node presentableNode; - - /** - * The cursor node. - */ - @NotNull - private final Node cursorNode; - - /** - * The markers node. - */ - @NotNull - private final Node markersNode; - - /** - * The nodes for the placement of model controls. - */ - @Nullable - private Node moveTool, rotateTool, scaleTool; - - /** - * The transformation mode. - */ - @NotNull - private TransformationMode transformMode; - - /** - * Center of transformation. - */ - @Nullable - private Transform transformCenter; - - /** - * The original transformation. - */ - @Nullable - private Transform originalTransform; - - /** - * Object to transform. - */ - @Nullable - private Spatial toTransform; - - /** - * Current display model. - */ - @Nullable - private M currentModel; - - /** - * Material for selection. - */ - @Nullable - private Material selectionMaterial; - - /** - * The current type of transformation. - */ - @Nullable - private volatile TransformType transformType; - - /** - * The current direction of transformation. - */ - @Nullable - private PickedAxis pickedAxis; - - /** - * The difference between the previous point of transformation and new. - */ - private float transformDeltaX; - private float transformDeltaY; - private float transformDeltaZ; - - /** - * The plane for calculation transforms. - */ - @Nullable - private Node collisionPlane; - - /** - * Grid of the scene. - */ - @Nullable - private Node grid; - - /** - * The flag of visibility grid. - */ - private boolean showGrid; - - /** - * The flag of visibility selection. - */ - private boolean showSelection; - - /** - * The flag of existing active transformation. - */ - private boolean activeTransform; - - /** - * The flag of painting mode. - */ - private boolean paintingMode; - - public AbstractSceneEditor3DPart(@NotNull final T fileEditor) { - super(fileEditor); - this.cachedLights = DictionaryFactory.newObjectDictionary(); - this.cachedAudioNodes = DictionaryFactory.newObjectDictionary(); - this.cachedPresentableObjects = DictionaryFactory.newObjectDictionary(); - this.modelNode = new Node("TreeNode"); - this.modelNode.setUserData(KEY_MODEL_NODE, true); - this.selected = ArrayFactory.newArray(Spatial.class); - this.selectionShape = DictionaryFactory.newObjectDictionary(); - this.toolNode = new Node("ToolNode"); - this.transformToolNode = new Node("TransformToolNode"); - this.lightNodes = ArrayFactory.newArray(EditorLightNode.class); - this.audioNodes = ArrayFactory.newArray(EditorAudioNode.class); - this.presentableNodes = ArrayFactory.newArray(EditorPresentableNode.class); - this.lightNode = new Node("Lights"); - this.audioNode = new Node("Audio nodes"); - this.presentableNode = new Node("Presentable nodes"); - this.cursorNode = new Node("Cursor node"); - this.markersNode = new Node("Markers node"); - - final EditorCamera editorCamera = notNull(getEditorCamera()); - editorCamera.setDefaultHorizontalRotation(H_ROTATION); - editorCamera.setDefaultVerticalRotation(V_ROTATION); - - modelNode.attachChild(lightNode); - modelNode.attachChild(audioNode); - modelNode.attachChild(presentableNode); - - createCollisionPlane(); - createToolElements(); - createManipulators(); - setShowSelection(true); - setShowGrid(true); - setTransformMode(TransformationMode.GLOBAL); - setTransformType(TransformType.MOVE_TOOL); - setTransformDeltaX(Float.NaN); - } - - @Override - @JmeThread - protected void registerActionHandlers(@NotNull final ObjectDictionary actionHandlers) { - super.registerActionHandlers(actionHandlers); - final T fileEditor = getFileEditor(); - actionHandlers.put(KEY_S, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.S, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - actionHandlers.put(KEY_G, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.G, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - actionHandlers.put(KEY_R, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.R, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - actionHandlers.put(KEY_DEL, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.DELETE, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - } - - @Override - @JmeThread - protected void registerActionListener(@NotNull final InputManager inputManager) { - super.registerActionListener(inputManager); - inputManager.addListener(actionListener, KEY_S, KEY_G, KEY_R, KEY_DEL); - } - - @Override - @FromAnyThread - protected boolean needEditorCamera() { - return true; - } - - /** - * Get the light node. - * - * @return the node to place lights. - */ - @FromAnyThread - protected @NotNull Node getLightNode() { - return lightNode; - } - - /** - * Get the audio node. - * - * @return the node to place audio nodes. - */ - @FromAnyThread - protected @NotNull Node getAudioNode() { - return audioNode; - } - - /** - * Get the presentable node. - * - * @return the node to place presentable nodes. - */ - @FromAnyThread - protected @NotNull Node getPresentableNode() { - return presentableNode; - } - - /** - * Create collision plane. - */ - @FromAnyThread - private void createCollisionPlane() { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - final Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - final RenderState renderState = material.getAdditionalRenderState(); - renderState.setFaceCullMode(RenderState.FaceCullMode.Off); - renderState.setWireframe(true); - - final float size = 20000; - - final Geometry geometry = new Geometry("plane", new Quad(size, size)); - geometry.setMaterial(material); - geometry.setLocalTranslation(-size / 2, -size / 2, 0); - - collisionPlane = new Node(); - collisionPlane.attachChild(geometry); - } - - /** - * Create tool elements. - */ - @FromAnyThread - private void createToolElements() { - - selectionMaterial = createColorMaterial(new ColorRGBA(1F, 170 / 255F, 64 / 255F, 1F)); - grid = createGrid(); - - final Node toolNode = getToolNode(); - toolNode.attachChild(grid); - } - - @FromAnyThread - private @NotNull Node createGrid() { - - final Node gridNode = new Node("GridNode"); - - final ColorRGBA gridColor = new ColorRGBA(0.4f, 0.4f, 0.4f, 0.5f); - final ColorRGBA xColor = new ColorRGBA(1.0f, 0.1f, 0.1f, 0.5f); - final ColorRGBA zColor = new ColorRGBA(0.1f, 1.0f, 0.1f, 0.5f); - - final Material gridMaterial = createColorMaterial(gridColor); - gridMaterial.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); - - final Material xMaterial = createColorMaterial(xColor); - xMaterial.getAdditionalRenderState().setLineWidth(5); - - final Material zMaterial = createColorMaterial(zColor); - zMaterial.getAdditionalRenderState().setLineWidth(5); - - final int gridSize = getGridSize(); - - final Geometry grid = new Geometry("grid", new Grid(gridSize, gridSize, 1.0f)); - grid.setMaterial(gridMaterial); - grid.setQueueBucket(RenderQueue.Bucket.Transparent); - grid.setShadowMode(RenderQueue.ShadowMode.Off); - grid.setCullHint(Spatial.CullHint.Never); - grid.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); - - final Quad quad = new Quad(gridSize, gridSize); - final Geometry gridCollision = new Geometry("collision", quad); - gridCollision.setMaterial(createColorMaterial(gridColor)); - gridCollision.setQueueBucket(RenderQueue.Bucket.Transparent); - gridCollision.setShadowMode(RenderQueue.ShadowMode.Off); - gridCollision.setCullHint(Spatial.CullHint.Always); - gridCollision.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); - gridCollision.setLocalRotation(new Quaternion().fromAngles(AngleUtils.degreeToRadians(90), 0, 0)); - - gridNode.attachChild(grid); - gridNode.attachChild(gridCollision); - - // Red line for X axis - final Line xAxis = new Line(new Vector3f(-gridSize / 2, 0f, 0f), new Vector3f(gridSize / 2 - 1, 0f, 0f)); - - final Geometry gxAxis = new Geometry("XAxis", xAxis); - gxAxis.setModelBound(new BoundingBox()); - gxAxis.setShadowMode(RenderQueue.ShadowMode.Off); - gxAxis.setCullHint(Spatial.CullHint.Never); - gxAxis.setMaterial(xMaterial); - - gridNode.attachChild(gxAxis); - - // Blue line for Z axis - final Line zAxis = new Line(new Vector3f(0f, 0f, -gridSize / 2), new Vector3f(0f, 0f, gridSize / 2 - 1)); - - final Geometry gzAxis = new Geometry("ZAxis", zAxis); - gzAxis.setModelBound(new BoundingBox()); - gzAxis.setShadowMode(RenderQueue.ShadowMode.Off); - gzAxis.setCullHint(Spatial.CullHint.Never); - gzAxis.setMaterial(zMaterial); - - gridNode.attachChild(gzAxis); - - return gridNode; - } - - /** - * Get the grid size. - * - * @return the grid size. - */ - @FromAnyThread - protected int getGridSize() { - return 20; - } - - /** - * Create manipulators. - */ - @FromAnyThread - private void createManipulators() { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - final Material redMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - redMaterial.setColor("Color", ColorRGBA.Red); - - final Material blueMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - blueMaterial.setColor("Color", ColorRGBA.Blue); - - final Material greenMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - greenMaterial.setColor("Color", ColorRGBA.Green); - - moveTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_move.j3o"); - moveTool.getChild("move_x").setMaterial(redMaterial); - moveTool.getChild("collision_move_x").setMaterial(redMaterial); - moveTool.getChild("collision_move_x").setCullHint(Spatial.CullHint.Always); - moveTool.getChild("move_y").setMaterial(blueMaterial); - moveTool.getChild("collision_move_y").setMaterial(blueMaterial); - moveTool.getChild("collision_move_y").setCullHint(Spatial.CullHint.Always); - moveTool.getChild("move_z").setMaterial(greenMaterial); - moveTool.getChild("collision_move_z").setMaterial(greenMaterial); - moveTool.getChild("collision_move_z").setCullHint(Spatial.CullHint.Always); - moveTool.scale(0.2f); - moveTool.addControl(new MoveToolControl(this)); - - rotateTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_rotate.j3o"); - rotateTool.getChild("rot_x").setMaterial(redMaterial); - rotateTool.getChild("collision_rot_x").setMaterial(redMaterial); - rotateTool.getChild("collision_rot_x").setCullHint(Spatial.CullHint.Always); - rotateTool.getChild("rot_y").setMaterial(blueMaterial); - rotateTool.getChild("collision_rot_y").setMaterial(blueMaterial); - rotateTool.getChild("collision_rot_y").setCullHint(Spatial.CullHint.Always); - rotateTool.getChild("rot_z").setMaterial(greenMaterial); - rotateTool.getChild("collision_rot_z").setMaterial(greenMaterial); - rotateTool.getChild("collision_rot_z").setCullHint(Spatial.CullHint.Always); - rotateTool.scale(0.2f); - rotateTool.addControl(new RotationToolControl(this)); - - scaleTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_scale.j3o"); - scaleTool.getChild("scale_x").setMaterial(redMaterial); - scaleTool.getChild("collision_scale_x").setMaterial(redMaterial); - scaleTool.getChild("collision_scale_x").setCullHint(Spatial.CullHint.Always); - scaleTool.getChild("scale_y").setMaterial(blueMaterial); - scaleTool.getChild("collision_scale_y").setMaterial(blueMaterial); - scaleTool.getChild("collision_scale_y").setCullHint(Spatial.CullHint.Always); - scaleTool.getChild("scale_z").setMaterial(greenMaterial); - scaleTool.getChild("collision_scale_z").setMaterial(greenMaterial); - scaleTool.getChild("collision_scale_z").setCullHint(Spatial.CullHint.Always); - scaleTool.scale(0.2f); - scaleTool.addControl(new ScaleToolControl(this)); - } - - /** - * Create the material to present selected models. - */ - @FromAnyThread - private @NotNull Material createColorMaterial(@NotNull final ColorRGBA color) { - final Material material = new Material(EditorUtil.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); - material.getAdditionalRenderState().setWireframe(true); - material.setColor("Color", color); - return material; - } - - /** - * Set the transform type. - * - * @param transformType the current transformation type. - */ - @FromAnyThread - public void setTransformType(@Nullable final TransformType transformType) { - this.transformType = transformType; - } - - /** - * Set the transform mode. - * - * @param transformMode the current transformation mode. - */ - @FromAnyThread - public void setTransformMode(@NotNull final TransformationMode transformMode) { - this.transformMode = transformMode; - } - - /** - * Get the node to place of transform controls. - * - * @return the node to place of transform controls. - */ - @FromAnyThread - private @NotNull Node getTransformToolNode() { - return transformToolNode; - } - - /** - * Get the transform type. - * - * @return the current transformation type. - */ - @FromAnyThread - public @Nullable TransformType getTransformType() { - return transformType; - } - - @Override - @JmeThread - public @NotNull TransformationMode getTransformationMode() { - return transformMode; - } - - @Override - @JmeThread - public @Nullable Transform getTransformCenter() { - return transformCenter; - } - - @Override - @JmeThread - public void setPickedAxis(@NotNull final PickedAxis axis) { - this.pickedAxis = axis; - } - - @Override - @JmeThread - public @NotNull PickedAxis getPickedAxis() { - return notNull(pickedAxis); - } - - @Override - @JmeThread - public @Nullable Node getCollisionPlane() { - if (collisionPlane == null) throw new RuntimeException("collisionPlane is null"); - return collisionPlane; - } - - @Override - @JmeThread - public void setTransformDeltaX(final float transformDeltaX) { - this.transformDeltaX = transformDeltaX; - } - - @Override - @JmeThread - public void setTransformDeltaY(final float transformDeltaY) { - this.transformDeltaY = transformDeltaY; - } - - @Override - @JmeThread - public void setTransformDeltaZ(final float transformDeltaZ) { - this.transformDeltaZ = transformDeltaZ; - } - - @Override - @JmeThread - public float getTransformDeltaX() { - return transformDeltaX; - } - - @Override - @JmeThread - public float getTransformDeltaY() { - return transformDeltaY; - } - - @Override - @JmeThread - public float getTransformDeltaZ() { - return transformDeltaZ; - } - - @Override - @JmeThread - public @Nullable Spatial getToTransform() { - return toTransform; - } - - /** - * Get the tool node. - * - * @return the node to place tool controls. - */ - @FromAnyThread - protected @NotNull Node getToolNode() { - return toolNode; - } - - /** - * Get the grid. - * - * @return grid of the scene. - */ - @FromAnyThread - private @NotNull Node getGrid() { - return notNull(grid); - } - - /** - * Get the node to place move tool controls. - * - * @return the node to place move tool controls. - */ - @FromAnyThread - private @NotNull Node getMoveTool() { - return notNull(moveTool); - } - - /** - * Get the node to place rotation tool controls. - * - * @return the node to place rotation tool controls. - */ - @FromAnyThread - private @NotNull Node getRotateTool() { - return notNull(rotateTool); - } - - /** - * Get the node to place scale tool controls. - * - * @return the node to place scale tool controls. - */ - @FromAnyThread - private @NotNull Node getScaleTool() { - return notNull(scaleTool); - } - - /** - * Set true of we have active transformation. - * - * @param activeTransform true of we have active transformation. - */ - @FromAnyThread - private void setActiveTransform(final boolean activeTransform) { - this.activeTransform = activeTransform; - } - - /** - * Return true of we have active transformation. - * - * @return true of we have active transformation. - */ - @FromAnyThread - private boolean isActiveTransform() { - return activeTransform; - } - - @Override - protected void preCameraUpdate(final float tpf) { - super.preCameraUpdate(tpf); - - final Node transformToolNode = getTransformToolNode(); - final Transform selectionCenter = getTransformCenter(); - final TransformType transformType = getTransformType(); - - // Transform Selected Objects! - if (isActiveTransform() && selectionCenter != null) { - if (transformType == TransformType.MOVE_TOOL) { - final TransformControl control = getMoveTool().getControl(TransformControl.class); - transformToolNode.detachAllChildren(); - control.processTransform(); - } else if (transformType == TransformType.ROTATE_TOOL) { - final TransformControl control = getRotateTool().getControl(TransformControl.class); - transformToolNode.detachAllChildren(); - control.processTransform(); - } else if (transformType == TransformType.SCALE_TOOL) { - final TransformControl control = getScaleTool().getControl(TransformControl.class); - transformToolNode.detachAllChildren(); - control.processTransform(); - } - } - } - - @Override - protected void postCameraUpdate(final float tpf) { - super.postCameraUpdate(tpf); - - final Array lightNodes = getLightNodes(); - lightNodes.forEach(EditorLightNode::updateModel); - - final Array audioNodes = getAudioNodes(); - audioNodes.forEach(EditorAudioNode::updateModel); - - final Array presentableNodes = getPresentableNodes(); - presentableNodes.forEach(EditorPresentableNode::updateModel); - - final Array selected = getSelected(); - selected.forEach(this, (spatial, state) -> { - - if (spatial instanceof EditorLightNode) { - spatial = ((EditorLightNode) spatial).getModel(); - } else if (spatial instanceof EditorAudioNode) { - spatial = ((EditorAudioNode) spatial).getModel(); - } else if (spatial instanceof EditorPresentableNode) { - spatial = ((EditorPresentableNode) spatial).getModel(); - } - - if (spatial == null) { - return; - } - - state.updateTransformNode(spatial.getWorldTransform()); - - final ObjectDictionary selectionShape = state.getSelectionShape(); - final Geometry shape = selectionShape.get(spatial); - if (shape == null) { - return; - } - - final Vector3f position = shape.getLocalTranslation(); - position.set(spatial.getWorldTranslation()); - - final Vector3f center = shape.getUserData(KEY_SHAPE_CENTER); - final Vector3f initScale = shape.getUserData(KEY_SHAPE_INIT_SCALE); - - if (center != null) { - - if (!initScale.equals(spatial.getLocalScale())) { - - initScale.set(spatial.getLocalScale()); - - NodeUtils.updateWorldBound(spatial); - - final BoundingBox bound = (BoundingBox) spatial.getWorldBound(); - bound.getCenter().subtract(spatial.getWorldTranslation(), center); - - final WireBox mesh = (WireBox) shape.getMesh(); - mesh.updatePositions(bound.getXExtent(), bound.getYExtent(), bound.getZExtent()); - } - - position.addLocal(center); - - } else { - shape.setLocalRotation(spatial.getWorldRotation()); - shape.setLocalScale(spatial.getWorldScale()); - } - - shape.setLocalTranslation(position); - }); - - transformToolNode.detachAllChildren(); - - if (transformType == TransformType.MOVE_TOOL) { - transformToolNode.attachChild(getMoveTool()); - } else if (transformType == TransformType.ROTATE_TOOL) { - transformToolNode.attachChild(getRotateTool()); - } else if (transformType == TransformType.SCALE_TOOL) { - transformToolNode.attachChild(getScaleTool()); - } - - final Node toolNode = getToolNode(); - - // FIXME change when will support transform multi-nodes - if (selected.size() != 1) { - toolNode.detachChild(transformToolNode); - } else if (!isPaintingMode()) { - toolNode.attachChild(transformToolNode); - } - - if (isPaintingMode()) { - updatePaintingNodes(); - updatePainting(tpf); - } - } - - /** - * Update editing nodes. - */ - @JmeThread - private void updatePaintingNodes() { - - if (!isPaintingMode()) { - return; - } - - final Node cursorNode = getCursorNode(); - final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); - final Spatial paintedModel = PaintingUtils.getPaintedModel(control); - if (paintedModel == null) { - return; - } - - final CollisionResults collisions = GeomUtils.getCollisionsFromCursor(paintedModel, getCamera()); - if (collisions.size() < 1) { - return; - } - - CollisionResult result = null; - - for (final CollisionResult collision : collisions) { - - final Geometry geometry = collision.getGeometry(); - final Object parent = NodeUtils.findParent(geometry, spatial -> - spatial.getUserData(KEY_IGNORE_RAY_CAST) == Boolean.TRUE); - - if (parent == null) { - result = collision; - break; - } - } - - if (result == null) { - result = collisions.getClosestCollision(); - } - - final Vector3f contactPoint = result.getContactPoint(); - final Vector3f contactNormal = result.getContactNormal(); - - final LocalObjects local = LocalObjects.get(); - final Quaternion rotation = local.nextRotation(); - rotation.lookAt(contactNormal, Vector3f.UNIT_Y); - - cursorNode.setLocalRotation(rotation); - cursorNode.setLocalTranslation(contactPoint); - } - - /** - * Update the transformation node. - */ - @JmeThread - private void updateTransformNode(@Nullable final Transform transform) { - - if (transform == null) { - return; - } - - final TransformationMode transformationMode = getTransformationMode(); - final Vector3f location = transform.getTranslation(); - final Vector3f positionOnCamera = getPositionOnCamera(location); - - final Node transformToolNode = getTransformToolNode(); - transformToolNode.setLocalTranslation(positionOnCamera); - transformToolNode.setLocalScale(1.5F); - transformToolNode.setLocalRotation(transformationMode.getToolRotation(transform, getCamera())); - } - - @JmeThread - private @NotNull Vector3f getPositionOnCamera(@NotNull final Vector3f location) { - - final LocalObjects local = LocalObjects.get(); - final Camera camera = EditorUtil.getGlobalCamera(); - - final Vector3f cameraLocation = camera.getLocation(); - final Vector3f resultPosition = location.subtract(cameraLocation, local.nextVector()) - .normalizeLocal() - .multLocal(camera.getFrustumNear() + 0.5f); - - return cameraLocation.add(resultPosition, local.nextVector()); - } - - /** - * Get the material of selection. - * - * @return the material of selection. - */ - @FromAnyThread - private @Nullable Material getSelectionMaterial() { - return selectionMaterial; - } - - /** - * Get the array of selected models. - * - * @return the array of selected models. - */ - @FromAnyThread - private @NotNull Array getSelected() { - return selected; - } - - /** - * Get the selection models of selected models. - * - * @return the selection models of selected models. - */ - @FromAnyThread - private @NotNull ObjectDictionary getSelectionShape() { - return selectionShape; - } - - /** - * Get the array of light nodes. - * - * @return the array of light nodes. - */ - @FromAnyThread - private @NotNull Array getLightNodes() { - return lightNodes; - } - - /** - * Get the array of audio nodes. - * - * @return the array of audio nodes. - */ - @FromAnyThread - private @NotNull Array getAudioNodes() { - return audioNodes; - } - - /** - * Get the array of presentable nodes. - * - * @return the array of presentable nodes. - */ - @FromAnyThread - private @NotNull Array getPresentableNodes() { - return presentableNodes; - } - - /** - * Get the map with cached light nodes. - * - * @return the map with cached light nodes. - */ - @FromAnyThread - private @NotNull ObjectDictionary getCachedLights() { - return cachedLights; - } - - /** - * Get the map with cached audio nodes. - * - * @return the map with cached audio nodes. - */ - @FromAnyThread - private @NotNull ObjectDictionary getCachedAudioNodes() { - return cachedAudioNodes; - } - - /** - * Get the map with cached presentable objects. - * - * @return the map with cached presentable objects. - */ - @FromAnyThread - private @NotNull ObjectDictionary getCachedPresentableObjects() { - return cachedPresentableObjects; - } - - /** - * Select the objects. - * - * @param objects the objects. - */ - @FromAnyThread - public void select(@NotNull final Array objects) { - EXECUTOR_MANAGER.addJmeTask(() -> selectImpl(objects)); - } - - /** - * Select the object. - * - * @param object the object. - */ - @FromAnyThread - public void select(@NotNull final Spatial object) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final Array toSelect = LocalObjects.get().nextSpatialArray(); - toSelect.add(object); - - selectImpl(toSelect); - }); - } - - /** - * The process of selecting the objects. - * - * @param objects the objects. - */ - @JmeThread - private void selectImpl(@NotNull final Array objects) { - - final Array selected = getSelected(); - - if (objects.isEmpty()) { - selected.forEach(this, (spatial, ed) -> ed.removeFromSelection(spatial)); - selected.clear(); - } else { - - for (final ArrayIterator iterator = selected.iterator(); iterator.hasNext(); ) { - - final Spatial spatial = iterator.next(); - if (objects.contains(spatial)) { - continue; - } - - removeFromSelection(spatial); - iterator.fastRemove(); - } - - for (final Spatial spatial : objects) { - if (!selected.contains(spatial)) { - addToSelection(spatial); - } - } - } - - updateToTransform(); - } - - /** - * Update transformation. - */ - @FromAnyThread - private void updateToTransform() { - setToTransform(getSelected().first()); - } - - /** - * Get the original transformation. - * - * @return the original transformation. - */ - @FromAnyThread - private @Nullable Transform getOriginalTransform() { - return originalTransform; - } - - /** - * Get the original transformation. - * - * @param originalTransform the original transformation. - */ - @FromAnyThread - private void setOriginalTransform(@Nullable final Transform originalTransform) { - this.originalTransform = originalTransform; - } - - /** - * Update the transformation's center. - */ - @JmeThread - private void updateTransformCenter() { - - final Spatial toTransform = getToTransform(); - final Transform transform = toTransform == null ? null : toTransform.getLocalTransform().clone(); - final Transform originalTransform = transform == null ? null : transform.clone(); - - setTransformCenter(transform); - setOriginalTransform(originalTransform); - } - - /** - * Add the spatial to selection. - */ - @JmeThread - private void addToSelection(@NotNull final Spatial spatial) { - - if (spatial instanceof VisibleOnlyWhenSelected) { - spatial.setCullHint(Spatial.CullHint.Dynamic); - } - - final Array selected = getSelected(); - selected.add(spatial); - - if (spatial instanceof NoSelection) { - return; - } - - Geometry shape; - - if (spatial instanceof ParticleEmitter) { - shape = buildBoxSelection(spatial); - } else if (spatial instanceof Geometry) { - shape = buildGeometrySelection((Geometry) spatial); - } else { - shape = buildBoxSelection(spatial); - } - - if (shape == null) { - return; - } - - if (isShowSelection()) { - final Node toolNode = getToolNode(); - toolNode.attachChild(shape); - } - - final ObjectDictionary selectionShape = getSelectionShape(); - selectionShape.put(spatial, shape); - } - - /** - * Remove the spatial from the selection. - */ - @JmeThread - private void removeFromSelection(@NotNull final Spatial spatial) { - setTransformCenter(null); - setToTransform(null); - - final ObjectDictionary selectionShape = getSelectionShape(); - - final Spatial shape = selectionShape.remove(spatial); - if (shape != null) { - shape.removeFromParent(); - } - - if (spatial instanceof VisibleOnlyWhenSelected) { - spatial.setCullHint(Spatial.CullHint.Always); - } - } - - /** - * Build the selection box for the spatial. - */ - @JmeThread - private Geometry buildBoxSelection(@NotNull final Spatial spatial) { - NodeUtils.updateWorldBound(spatial); - - final BoundingVolume bound = spatial.getWorldBound(); - - if (bound instanceof BoundingBox) { - - final BoundingBox boundingBox = (BoundingBox) bound; - final Vector3f center = boundingBox.getCenter().subtract(spatial.getWorldTranslation()); - final Vector3f initScale = spatial.getLocalScale().clone(); - - final Geometry geometry = WireBox.makeGeometry(boundingBox); - geometry.setName("SelectionShape"); - geometry.setMaterial(getSelectionMaterial()); - geometry.setUserData(KEY_SHAPE_CENTER, center); - geometry.setUserData(KEY_SHAPE_INIT_SCALE, initScale); - - final Vector3f position = geometry.getLocalTranslation(); - position.addLocal(center); - - geometry.setLocalTranslation(position); - - return geometry; - - } else if (bound instanceof BoundingSphere) { - - final BoundingSphere boundingSphere = (BoundingSphere) bound; - - final WireSphere wire = new WireSphere(); - wire.fromBoundingSphere(boundingSphere); - - final Geometry geometry = new Geometry("SelectionShape", wire); - geometry.setMaterial(getSelectionMaterial()); - geometry.setLocalTranslation(spatial.getWorldTranslation()); - - return geometry; - } - - final Geometry geometry = WireBox.makeGeometry(new BoundingBox(Vector3f.ZERO, 1, 1, 1)); - geometry.setName("SelectionShape"); - geometry.setMaterial(getSelectionMaterial()); - geometry.setLocalTranslation(spatial.getWorldTranslation()); - - return geometry; - } - - /** - * Build selection grid for the geometry. - */ - @JmeThread - private Geometry buildGeometrySelection(@NotNull final Geometry geom) { - - final Mesh mesh = geom.getMesh(); - if (mesh == null) { - return null; - } - - final Geometry geometry = new Geometry("SelectionShape", mesh); - geometry.setMaterial(getSelectionMaterial()); - geometry.setLocalTransform(geom.getWorldTransform()); - - return geometry; - } - - /** - * @param showGrid the flag of visibility grid. - */ - @JmeThread - private void setShowGrid(final boolean showGrid) { - this.showGrid = showGrid; - } - - /** - * @param showSelection the flag of visibility selection. - */ - @JmeThread - private void setShowSelection(final boolean showSelection) { - this.showSelection = showSelection; - } - - /** - * @return true if the grid is showed. - */ - @JmeThread - private boolean isShowGrid() { - return showGrid; - } - - /** - * @return true if the selection is showed. - */ - @JmeThread - private boolean isShowSelection() { - return showSelection; - } - - @Override - @JmeThread - public void notifyTransformed(@NotNull final Spatial spatial) { - getFileEditor().notifyTransformed(spatial); - } - - /** - * Update showing selection. - * - * @param showSelection true if needs to show selection - */ - @FromAnyThread - public void updateShowSelection(final boolean showSelection) { - EXECUTOR_MANAGER.addJmeTask(() -> updateShowSelectionImpl(showSelection)); - } - - /** - * Update showing selection. - * - * @param showSelection true if needs to show selection - */ - @JmeThread - private void updateShowSelectionImpl(final boolean showSelection) { - - if (isShowSelection() == showSelection) { - return; - } - - final ObjectDictionary selectionShape = getSelectionShape(); - final Node toolNode = getToolNode(); - - if (showSelection && !selectionShape.isEmpty()) { - selectionShape.forEach(toolNode::attachChild); - } else if (!showSelection && !selectionShape.isEmpty()) { - selectionShape.forEach(toolNode::detachChild); - } - - setShowSelection(showSelection); - } - - @Override - @JmeThread - protected void onActionImpl(@NotNull final String name, final boolean isPressed, final float tpf) { - super.onActionImpl(name, isPressed, tpf); - if (MOUSE_RIGHT_CLICK.equals(name)) { - if(isPaintingMode()) { - if (isPressed) startPainting(getPaintingInput(MouseButton.SECONDARY)); - else finishPainting(getPaintingInput(MouseButton.SECONDARY)); - } else if(!isPressed) { - processSelect(); - } - } else if (MOUSE_LEFT_CLICK.equals(name)) { - if (isPaintingMode()) { - if (isPressed) { - startPainting(getPaintingInput(MouseButton.PRIMARY)); - } else { - finishPainting(getPaintingInput(MouseButton.PRIMARY)); - } - } else { - if (isPressed) { - startTransform(); - } else { - endTransform(); - } - } - } - } - - /** - * Get the painting input. - * - * @param mouseButton the mouse button. - * @return the painting input. - */ - @FromAnyThread - protected @NotNull PaintingInput getPaintingInput(@NotNull final MouseButton mouseButton) { - switch (mouseButton) { - case SECONDARY: { - - if (isControlDown()) { - return PaintingInput.MOUSE_SECONDARY_WITH_CTRL; - } - - return PaintingInput.MOUSE_SECONDARY; - } - case PRIMARY: { - return PaintingInput.MOUSE_PRIMARY; - } - } - - return PaintingInput.MOUSE_PRIMARY; - } - - /** - * Handling a click in the area of the editor. - */ - @JmeThread - private void processSelect() { - - if (isPaintingMode()) { - return; - } - - final Node modelNode = notNull(getModelNode()); - final Geometry anyGeometry = GeomUtils.getGeometryFromCursor(modelNode, getCamera()); - final M currentModel = notNull(getCurrentModel()); - - Object toSelect = anyGeometry == null ? null : findToSelect(anyGeometry); - - if (toSelect == null && anyGeometry != null) { - final Geometry modelGeometry = GeomUtils.getGeometryFromCursor(currentModel, getCamera()); - toSelect = modelGeometry == null ? null : findToSelect(modelGeometry); - } - - final Object result = toSelect; - - EXECUTOR_MANAGER.addFxTask(() -> notifySelected(result)); - } - - /** - * Find to select object. - * - * @param object the object - * @return the object - */ - @JmeThread - protected @Nullable Object findToSelect(@NotNull final Object object) { - - for (final Function finder : SELECTION_FINDERS) { - final Spatial spatial = finder.apply(object); - if (spatial != null && spatial.isVisible()) { - return spatial; - } - } - - if (object instanceof Geometry) { - - final Spatial spatial = (Spatial) object; - - Spatial parent = NodeUtils.findParent(spatial, 2); - - final EditorLightNode lightNode = parent == null ? null : getLightNode(parent); - if (lightNode != null) { - return lightNode; - } - - final EditorAudioNode audioNode = parent == null ? null : getAudioNode(parent); - if (audioNode != null) { - return audioNode; - } - - parent = NodeUtils.findParent(spatial, AssetLinkNode.class::isInstance); - if (parent != null) { - return parent; - } - - parent = NodeUtils.findParent(spatial, p -> Boolean.TRUE.equals(p.getUserData(KEY_LOADED_MODEL))); - if (parent != null) { - return parent; - } - } - - if (object instanceof Spatial) { - - final Spatial spatial = (Spatial) object; - - if (!spatial.isVisible()) { - return null; - } else if (findParent(spatial, sp -> !sp.isVisible()) != null) { - return null; - } else if (findParent(spatial, sp -> sp == getCurrentModel()) == null) { - return null; - } - } - - return object; - } - - /** - * Get a geometry on a scene for a position on a screen. - * - * @param screenX the x position on screen. - * @param screenY the y position on screen. - * @return the position on a scene. - */ - @JmeThread - public @Nullable Geometry getGeometryByScreenPos(final float screenX, final float screenY) { - return GeomUtils.getGeometryFromScreenPos(notNull(getCurrentModel()), getCamera(), screenX, screenY); - } - - @JmeThread - private void notifySelected(@Nullable final Object object) { - getFileEditor().notifySelected(object); - } - - /** - * Get a position on a scene for a cursor position. - * - * @param screenX the x position on screen. - * @param screenY the y position on screen. - * @return the position on a scene. - */ - @JmeThread - public @NotNull Vector3f getScenePosByScreenPos(final float screenX, final float screenY) { - - final Camera camera = getCamera(); - final M currentModel = notNull(getCurrentModel()); - - final Vector3f modelPoint = GeomUtils.getContactPointFromScreenPos(currentModel, camera, screenX, screenY); - final Vector3f gridPoint = GeomUtils.getContactPointFromScreenPos(getGrid(), camera, screenX, screenY); - - if (modelPoint == null) { - return gridPoint == null ? Vector3f.ZERO : gridPoint; - } else if (gridPoint == null) { - return modelPoint; - } - - final float distance = modelPoint.distance(camera.getLocation()); - - if (gridPoint.distance(camera.getLocation()) < distance) { - return gridPoint; - } else { - return modelPoint; - } - } - - /** - * Get a normal on a scene for a cursor position. - * - * @param screenX the x position on screen. - * @param screenY the y position on screen. - * @return the normal on the current scene or null. - */ - @JmeThread - public @Nullable Vector3f getSceneNormalByScreenPos(final float screenX, final float screenY) { - final Camera camera = getCamera(); - final M currentModel = notNull(getCurrentModel()); - return GeomUtils.getContactNormalFromScreenPos(currentModel, camera, screenX, screenY); - } - - /** - * Get the node to place models. - * - * @return the node to place models. - */ - protected @NotNull Node getModelNode() { - return modelNode; - } - - /** - * Update the showing grid. - * - * @param showGrid the show grid - */ - @FromAnyThread - public void updateShowGrid(final boolean showGrid) { - EXECUTOR_MANAGER.addJmeTask(() -> updateShowGridImpl(showGrid)); - } - - /** - * The process of updating the showing grid. - */ - @JmeThread - private void updateShowGridImpl(final boolean showGrid) { - if (isShowGrid() == showGrid) return; - - final Node toolNode = getToolNode(); - final Node grid = getGrid(); - - if (showGrid) { - toolNode.attachChild(grid); - } else { - toolNode.detachChild(grid); - } - - setShowGrid(showGrid); - } - - /** - * Finish the transformation of the model. - */ - @JmeThread - private void endTransform() { - if (!isActiveTransform()) { - return; - } - - final Transform originalTransform = getOriginalTransform(); - final Spatial toTransform = getToTransform(); - final Spatial currentModel = getCurrentModel(); - - if (currentModel == null) { - LOGGER.warning(this, "not found current model for finishing transform..."); - return; - } else if (originalTransform == null || toTransform == null) { - LOGGER.warning(this, "not found originalTransform or toTransform"); - return; - } - - POST_TRANSFORM_HANDLERS.forEach(toTransform, Consumer::accept); - - final Transform oldValue = originalTransform.clone(); - final Transform newValue = toTransform.getLocalTransform().clone(); - - final PropertyOperation operation = - new PropertyOperation<>(toTransform, "internal_transformation", newValue, oldValue); - - operation.setApplyHandler((spatial, transform) -> { - PRE_TRANSFORM_HANDLERS.forEach(spatial, Consumer::accept); - try { - spatial.setLocalTransform(transform); - } finally { - POST_TRANSFORM_HANDLERS.forEach(spatial, Consumer::accept); - } - }); - - final T fileEditor = getFileEditor(); - fileEditor.execute(operation); - - setPickedAxis(PickedAxis.NONE); - setActiveTransform(false); - setTransformDeltaX(Float.NaN); - updateTransformCenter(); - } - - /** - * Start transformation. - */ - @JmeThread - private boolean startTransform() { - updateTransformCenter(); - - final Camera camera = EditorUtil.getGlobalCamera(); - final InputManager inputManager = EditorUtil.getInputManager(); - final Vector2f cursorPosition = inputManager.getCursorPosition(); - - final CollisionResults collisionResults = new CollisionResults(); - - final Vector3f position = camera.getWorldCoordinates(cursorPosition, 0f); - final Vector3f direction = camera.getWorldCoordinates(cursorPosition, 1f); - direction.subtractLocal(position).normalizeLocal(); - - final Ray ray = new Ray(); - ray.setOrigin(position); - ray.setDirection(direction); - - final Node transformToolNode = getTransformToolNode(); - transformToolNode.collideWith(ray, collisionResults); - - if (collisionResults.size() < 1) { - return false; - } - - final Spatial toTransform = getToTransform(); - if (toTransform != null) { - PRE_TRANSFORM_HANDLERS.forEach(toTransform, Consumer::accept); - } - - final CollisionResult collisionResult = collisionResults.getClosestCollision(); - final TransformType transformType = getTransformType(); - - if (transformType == TransformType.MOVE_TOOL) { - final Node moveTool = getMoveTool(); - final TransformControl control = moveTool.getControl(TransformControl.class); - control.setCollisionPlane(collisionResult); - } else if (transformType == TransformType.ROTATE_TOOL) { - final Node rotateTool = getRotateTool(); - final TransformControl control = rotateTool.getControl(TransformControl.class); - control.setCollisionPlane(collisionResult); - } else if (transformType == TransformType.SCALE_TOOL) { - final Node scaleTool = getScaleTool(); - final TransformControl control = scaleTool.getControl(TransformControl.class); - control.setCollisionPlane(collisionResult); - } - - setActiveTransform(true); - return true; - } - - /** - * Start painting. - */ - @JmeThread - private void startPainting(@NotNull final PaintingInput input) { - - final Node cursorNode = getCursorNode(); - final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); - final Spatial paintedModel = PaintingUtils.getPaintedModel(getCursorNode()); - - if (control == null || paintedModel == null || control.isStartedPainting()) { - return; - } - - control.startPainting(input, cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); - } - - /** - * Finish painting. - */ - @JmeThread - private void finishPainting(@NotNull final PaintingInput input) { - - final Node cursorNode = getCursorNode(); - final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); - final Spatial paintedModel = PaintingUtils.getPaintedModel(control); - - if (control == null || paintedModel == null) { - return; - } else if (!control.isStartedPainting() || control.getCurrentInput() != input) { - return; - } - - control.finishPainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); - } - - /** - * Update painting. - */ - @JmeThread - private void updatePainting(final float tpf) { - - final Node cursorNode = getCursorNode(); - final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); - final Spatial model = PaintingUtils.getPaintedModel(control); - - if (control == null || model == null || !control.isStartedPainting()) { - return; - } - - control.updatePainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation(), tpf); - } - - /** - * Notify about an attempt to change the property from jME thread. - * - * @param object the object. - * @param name the property name. - */ - @JmeThread - public void notifyPropertyPreChanged(@NotNull final Object object, @NotNull final String name) { - if (object instanceof Spatial) { - if (isTransformationProperty(name)) { - PRE_TRANSFORM_HANDLERS.forEach((Spatial) object, Consumer::accept); - } - } - } - - /** - * Notify about property changes. - * - * @param object the object with changes. - * @param name the property name. - */ - @JmeThread - public void notifyPropertyChanged(@NotNull Object object, @NotNull final String name) { - - if (object instanceof SimpleProperty) { - object = ((SimpleProperty) object).getObject(); - } - - if (object instanceof AudioNode) { - final EditorAudioNode node = getAudioNode((AudioNode) object); - if (node != null) node.sync(); - } else if (object instanceof Light) { - final EditorLightNode node = getLightNode((Light) object); - if (node != null) node.sync(); - } else if (object instanceof ScenePresentable) { - final EditorPresentableNode node = getPresentableNode((ScenePresentable) object); - if (node != null) node.sync(); - } - - if (object instanceof Spatial) { - if (isTransformationProperty(name)) { - POST_TRANSFORM_HANDLERS.forEach((Spatial) object, Consumer::accept); - } - } - } - - protected boolean isTransformationProperty(@NotNull final String name) { - return Messages.MODEL_PROPERTY_LOCATION.equals(name) || - Messages.MODEL_PROPERTY_SCALE.equals(name) || - Messages.MODEL_PROPERTY_ROTATION.equals(name) || - Messages.MODEL_PROPERTY_TRANSFORMATION.equals(name); - } - - /** - * @param toTransform the object to transform. - */ - @JmeThread - private void setToTransform(@Nullable final Spatial toTransform) { - this.toTransform = toTransform; - } - - /** - * @param transformCenter the center of transformation. - */ - @JmeThread - private void setTransformCenter(@Nullable final Transform transformCenter) { - this.transformCenter = transformCenter; - } - - /** - * Show the model in the scene. - * - * @param model the model - */ - @FromAnyThread - public void openModel(@NotNull final M model) { - EXECUTOR_MANAGER.addJmeTask(() -> openModelImpl(model)); - } - - /** - * The process of showing the model in the scene. - */ - @JmeThread - private void openModelImpl(@NotNull final M model) { - - final Node modelNode = getModelNode(); - final M currentModel = getCurrentModel(); - - if (currentModel != null) { - detachPrevModel(modelNode, currentModel); - } - - NodeUtils.visitGeometry(model, geometry -> { - - final RenderManager renderManager = EditorUtil.getRenderManager(); - try { - renderManager.preloadScene(geometry); - } catch (final RendererException | AssetNotFoundException | UnsupportedOperationException e) { - EditorUtil.handleException(LOGGER, this, - new RuntimeException("Found invalid material in the geometry: [" + geometry.getName() + "]. " + - "The material will be removed from the geometry.", e)); - geometry.setMaterial(EditorUtil.getDefaultMaterial()); - } - }); - - PRE_TRANSFORM_HANDLERS.forEach(model, Consumer::accept); - attachModel(model, modelNode); - POST_TRANSFORM_HANDLERS.forEach(model, Consumer::accept); - setCurrentModel(model); - } - - @JmeThread - protected void detachPrevModel(@NotNull final Node modelNode, @Nullable final M currentModel) { - if (currentModel != null) { - modelNode.detachChild(currentModel); - } - } - - @JmeThread - protected void attachModel(@NotNull final M model, @NotNull final Node modelNode) { - modelNode.attachChild(model); - } - - /** - * @param currentModel current display model. - */ - @JmeThread - private void setCurrentModel(@Nullable final M currentModel) { - this.currentModel = currentModel; - } - - /** - * Get the current model. - * - * @return current display model. - */ - @FromAnyThread - public @Nullable M getCurrentModel() { - return currentModel; - } - - /** - * Add the light. - * - * @param light the light. - */ - @FromAnyThread - public void addLight(@NotNull final Light light) { - EXECUTOR_MANAGER.addJmeTask(() -> addLightImpl(light)); - } - - /** - * The process of adding a light. - */ - @JmeThread - private void addLightImpl(@NotNull final Light light) { - - final Node node = LIGHT_MODEL_TABLE.get(light.getType()); - if (node == null) return; - - final ObjectDictionary cachedLights = getCachedLights(); - - final Camera camera = EditorUtil.getGlobalCamera(); - final EditorLightNode lightModel = notNull(cachedLights.get(light, () -> { - - final Node model = (Node) node.clone(); - model.setLocalScale(0.03F); - - final EditorLightNode result = new EditorLightNode(camera); - result.setModel(model); - - final Geometry geometry = NodeUtils.findGeometry(model, "White"); - - if (geometry == null) { - LOGGER.warning(this, "not found geometry for the node " + geometry); - return null; - } - - final Material material = geometry.getMaterial(); - material.setColor("Color", light.getColor()); - - return result; - })); - - lightModel.setLight(light); - lightModel.sync(); - - final Node lightNode = getLightNode(); - lightNode.attachChild(lightModel); - lightNode.attachChild(lightModel.getModel()); - - getLightNodes().add(lightModel); - } - - /** - * Move a camera to a location. - * - * @param location the location. - */ - @FromAnyThread - public void moveCameraTo(@NotNull final Vector3f location) { - EXECUTOR_MANAGER.addJmeTask(() -> getNodeForCamera().setLocalTranslation(location)); - } - - /** - * Look at the spatial. - * - * @param spatial the spatial. - */ - @FromAnyThread - public void cameraLookAt(@NotNull final Spatial spatial) { - EXECUTOR_MANAGER.addJmeTask(() -> { - - final EditorCamera editorCamera = notNull(getEditorCamera()); - - final LocalObjects local = LocalObjects.get(); - float distance; - - final BoundingVolume worldBound = spatial.getWorldBound(); - - if (worldBound != null) { - distance = worldBound.getVolume(); - - if (worldBound instanceof BoundingBox) { - final BoundingBox boundingBox = (BoundingBox) worldBound; - distance = boundingBox.getXExtent(); - distance = Math.max(distance, boundingBox.getYExtent()); - distance = Math.max(distance, boundingBox.getZExtent()); - distance *= 2F; - } else if (worldBound instanceof BoundingSphere) { - distance = ((BoundingSphere) worldBound).getRadius() * 2F; - } - - } else { - - distance = getCamera().getLocation() - .distance(spatial.getWorldTranslation()); - } - - editorCamera.setTargetDistance(distance); - - final Vector3f position = local.nextVector() - .set(spatial.getWorldTranslation()); - - getNodeForCamera().setLocalTranslation(position); - }); - } - - /** - * Remove the light. - * - * @param light the light. - */ - @FromAnyThread - public void removeLight(@NotNull final Light light) { - EXECUTOR_MANAGER.addJmeTask(() -> removeLightImpl(light)); - } - - /** - * The process of removing a light. - */ - @JmeThread - private void removeLightImpl(@NotNull final Light light) { - - final Node node = LIGHT_MODEL_TABLE.get(light.getType()); - if (node == null) { - return; - } - - final ObjectDictionary cachedLights = getCachedLights(); - final EditorLightNode lightModel = cachedLights.get(light); - if (lightModel == null) { - return; - } - - lightModel.setLight(null); - - final Node lightNode = getLightNode(); - lightNode.detachChild(lightModel); - lightNode.detachChild(notNull(lightModel.getModel())); - - getLightNodes().fastRemove(lightModel); - } - - /** - * Add the audio node. - * - * @param audioNode the audio node. - */ - @FromAnyThread - public void addAudioNode(@NotNull final AudioNode audioNode) { - EXECUTOR_MANAGER.addJmeTask(() -> addAudioNodeImpl(audioNode)); - } - - /** - * The process of adding the audio node. - */ - @JmeThread - private void addAudioNodeImpl(@NotNull final AudioNode audio) { - - final ObjectDictionary cachedAudioNodes = getCachedAudioNodes(); - - final EditorAudioNode audioModel = notNull(cachedAudioNodes.get(audio, () -> { - - final Node model = (Node) AUDIO_NODE_MODEL.clone(); - model.setLocalScale(0.01F); - - final EditorAudioNode result = new EditorAudioNode(getCamera()); - result.setModel(model); - - return result; - })); - - audioModel.setAudioNode(audio); - audioModel.sync(); - - final Node audioNode = getAudioNode(); - audioNode.attachChild(audioModel); - audioNode.attachChild(audioModel.getModel()); - - getAudioNodes().add(audioModel); - } - - /** - * Remove the audio node. - * - * @param audio the audio node. - */ - @FromAnyThread - public void removeAudioNode(@NotNull final AudioNode audio) { - EXECUTOR_MANAGER.addJmeTask(() -> removeAudioNodeImpl(audio)); - } - - /** - * The process of removing the audio node. - */ - @JmeThread - private void removeAudioNodeImpl(@NotNull final AudioNode audio) { - - final ObjectDictionary cachedAudioNodes = getCachedAudioNodes(); - final EditorAudioNode audioModel = cachedAudioNodes.get(audio); - if (audioModel == null) { - return; - } - - audioModel.setAudioNode(null); - - final Node audioNode = getAudioNode(); - audioNode.detachChild(audioModel); - audioNode.detachChild(notNull(audioModel.getModel())); - - getAudioNodes().fastRemove(audioModel); - } - - /** - * Add the presentable object. - * - * @param presentable the presentable object. - */ - @FromAnyThread - public void addPresentable(@NotNull final ScenePresentable presentable) { - EXECUTOR_MANAGER.addJmeTask(() -> addPresentableImpl(presentable)); - } - - /** - * The process of adding the presentable object. - */ - @JmeThread - private void addPresentableImpl(@NotNull final ScenePresentable presentable) { - - final ObjectDictionary cache = getCachedPresentableObjects(); - final EditorPresentableNode node = notNull(cache.get(presentable, () -> { - final EditorPresentableNode result = new EditorPresentableNode(); - result.setModel(createGeometry(presentable.getPresentationType())); - return result; - })); - - node.setObject(presentable); - node.sync(); - - final Node editedNode = node.getEditedNode(); - editedNode.setCullHint(Spatial.CullHint.Always); - - final Node presentableNode = getPresentableNode(); - presentableNode.attachChild(node); - presentableNode.attachChild(node.getModel()); - - node.setObject(presentable); - - getPresentableNodes().add(node); - } - - @JmeThread - protected @NotNull Geometry createGeometry(@NotNull final ScenePresentable.PresentationType presentationType) { - - final Material material = new Material(EditorUtil.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); - material.setColor("Color", ColorRGBA.Yellow); - material.getAdditionalRenderState().setWireframe(true); - - Geometry geometry; - - switch (presentationType) { - case SPHERE: { - geometry = new Geometry("Sphere", new Sphere(8, 8, 1)); - break; - } - default: { - geometry = new Geometry("Box", new Box(1, 1, 1)); - } - } - - geometry.setMaterial(material); - return geometry; - } - - /** - * Remove the audio node. - * - * @param presentable the presentable. - */ - @FromAnyThread - public void removePresentable(@NotNull final ScenePresentable presentable) { - EXECUTOR_MANAGER.addJmeTask(() -> removePresentableImpl(presentable)); - } - - /** - * The process of removing the audio node. - */ - @JmeThread - private void removePresentableImpl(@NotNull final ScenePresentable presentable) { - - final ObjectDictionary presentableNodes = getCachedPresentableObjects(); - final EditorPresentableNode node = presentableNodes.get(presentable); - if (node == null) { - return; - } - - node.setObject(null); - - final Node presentableNode = getPresentableNode(); - presentableNode.detachChild(node); - presentableNode.detachChild(notNull(node.getModel())); - - getPresentableNodes().fastRemove(node); - } - - /** - * Get a light node for thr light. - * - * @param light the light. - * @return the light node or null. - */ - @FromAnyThread - public @Nullable EditorLightNode getLightNode(@NotNull final Light light) { - return getLightNodes().search(light, (node, toCheck) -> node.getLight() == toCheck); - } - - /** - * Get a light node for the model. - * - * @param model the model. - * @return the light node or null. - */ - @FromAnyThread - public @Nullable EditorLightNode getLightNode(@NotNull final Spatial model) { - return getLightNodes().search(model, (node, toCheck) -> node.getModel() == toCheck); - } - - /** - * Get an editor audio node for the audio node. - * - * @param audioNode the audio node. - * @return the editor audio node or null. - */ - @FromAnyThread - public @Nullable EditorAudioNode getAudioNode(@NotNull final AudioNode audioNode) { - return getAudioNodes().search(audioNode, (node, toCheck) -> node.getAudioNode() == toCheck); - } - - /** - * Get an editor audio node for the model. - * - * @param model the model. - * @return the editor audio node or null. - */ - @FromAnyThread - public @Nullable EditorAudioNode getAudioNode(@NotNull final Spatial model) { - return getAudioNodes().search(model, (node, toCheck) -> node.getModel() == toCheck); - } - - /** - * Get an editor presentable node for the presentable object. - * - * @param presentable the presentable object. - * @return the editor presentable node or null. - */ - @FromAnyThread - public @Nullable EditorPresentableNode getPresentableNode(@NotNull final ScenePresentable presentable) { - return getPresentableNodes().search(presentable, (node, toCheck) -> node.getObject() == toCheck); - } - - /** - * Get an editor presentable node for the model. - * - * @param model the model. - * @return the editor presentable node or null. - */ - @FromAnyThread - public @Nullable EditorPresentableNode getPresentableNode(@NotNull final Spatial model) { - return getPresentableNodes().search(model, (node, toCheck) -> node.getModel() == toCheck); - } - - @Override - @JmeThread - protected void notifyChangedCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, - final float cameraSpeed) { - super.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed); - EXECUTOR_MANAGER.addFxTask(() -> getFileEditor().notifyChangedCameraSettings(cameraLocation, hRotation, - vRotation, targetDistance, cameraSpeed)); - } - - /** - * Set the flag of painting mode. - * - * @param paintingMode the flag of painting mode. - */ - @JmeThread - private void setPaintingMode(final boolean paintingMode) { - this.paintingMode = paintingMode; - } - - /** - * Return the flag of painting mode. - * - * @return true if painting mode is enabled. - */ - @JmeThread - private boolean isPaintingMode() { - return paintingMode; - } - - /** - * Change enabling of painting mode. - * - * @param paintingMode true if painting mode is enabled. - */ - @FromAnyThread - public void changePaintingMode(final boolean paintingMode) { - EXECUTOR_MANAGER.addJmeTask(() -> changePaintingModeImpl(paintingMode)); - } - - /** - * Change enabling of painting mode. - * - * @param paintingMode true if painting mode is enabled. - */ - @JmeThread - private void changePaintingModeImpl(final boolean paintingMode) { - setPaintingMode(paintingMode); - - final Node cursorNode = getCursorNode(); - final Node markersNode = getMarkersNode(); - final Node toolNode = getToolNode(); - final Node transformToolNode = getTransformToolNode(); - - if (isPaintingMode()) { - toolNode.attachChild(cursorNode); - toolNode.attachChild(markersNode); - toolNode.detachChild(transformToolNode); - } else { - toolNode.detachChild(cursorNode); - toolNode.detachChild(markersNode); - toolNode.attachChild(transformToolNode); - } - } - - /** - * Get the cursor node. - * - * @return the cursor node. - */ - @JmeThread - public @NotNull Node getCursorNode() { - return cursorNode; - } - - /** - * Get the markers node. - * - * @return the markers node. - */ - @JmeThread - public @NotNull Node getMarkersNode() { - return markersNode; - } - - @Override - @JmeThread - public @NotNull Camera getCamera() { - return EditorUtil.getGlobalCamera(); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java deleted file mode 100644 index e85725e7..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.ss.editor.part3d.editor.impl.scene; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_FXAA_FILTER; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TONEMAP_FILTER; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_FILTER_FXAA; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_FILTER_TONEMAP; -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.FXAAFilter; -import com.jme3.post.filters.ToneMapFilter; -import com.jme3.scene.Node; -import com.ss.editor.JmeApplication; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.ui.component.editor.impl.scene.SceneFileEditor; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link AbstractSceneEditor3DPart} for the {@link SceneFileEditor}. - * - * @author JavaSaBr - */ -public class SceneEditor3DPart extends AbstractSceneEditor3DPart { - - /** - * The flag of showing light models. - */ - private boolean lightShowed; - - /** - * The flag of showing audio models. - */ - private boolean audioShowed; - - public SceneEditor3DPart(@NotNull final SceneFileEditor fileEditor) { - super(fileEditor); - - this.lightShowed = true; - this.audioShowed = true; - - final Node stateNode = getStateNode(); - stateNode.attachChild(getModelNode()); - stateNode.attachChild(getToolNode()); - } - - @Override - @JmeThread - protected int getGridSize() { - return 1000; - } - - @Override - @JmeThread - protected void attachModel(@NotNull final SceneNode model, @NotNull final Node modelNode) { - } - - @Override - @JmeThread - protected void detachPrevModel(@NotNull final Node modelNode, @Nullable final SceneNode currentModel) { - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - - final SceneNode currentModel = getCurrentModel(); - - if (currentModel != null) { - getModelNode().attachChild(currentModel); - } - - final JmeApplication jmeApplication = JmeApplication.getInstance(); - final FXAAFilter fxaaFilter = jmeApplication.getFXAAFilter(); - fxaaFilter.setEnabled(false); - - final ToneMapFilter toneMapFilter = jmeApplication.getToneMapFilter(); - toneMapFilter.setEnabled(false); - } - - @Override - @JmeThread - public void cleanup() { - super.cleanup(); - - final SceneNode currentModel = getCurrentModel(); - - if (currentModel != null) { - getModelNode().detachChild(currentModel); - } - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final JmeApplication jmeApplication = JmeApplication.getInstance(); - - final FXAAFilter fxaaFilter = jmeApplication.getFXAAFilter(); - fxaaFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER)); - - final ToneMapFilter toneMapFilter = jmeApplication.getToneMapFilter(); - toneMapFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER)); - } - - /** - * Add a scene app state. - * - * @param appState the scene app state. - */ - @FromAnyThread - public void addAppState(@NotNull final SceneAppState appState) { - EXECUTOR_MANAGER.addJmeTask(() -> addAppStateImpl(appState)); - } - - @JmeThread - private void addAppStateImpl(@NotNull final SceneAppState appState) { - final AppStateManager stateManager = EditorUtil.getStateManager(); - stateManager.attach(appState); - } - - /** - * Remove a scene app state. - * - * @param appState the scene app state. - */ - @FromAnyThread - public void removeAppState(@NotNull final SceneAppState appState) { - EXECUTOR_MANAGER.addJmeTask(() -> removeAppStateImpl(appState)); - } - - @JmeThread - private void removeAppStateImpl(@NotNull final SceneAppState appState) { - final AppStateManager stateManager = EditorUtil.getStateManager(); - stateManager.detach(appState); - } - - /** - * Add a scene filter. - * - * @param sceneFilter the scene filter. - */ - @FromAnyThread - public void addFilter(@NotNull final SceneFilter sceneFilter) { - EXECUTOR_MANAGER.addJmeTask(() -> addFilterImpl(sceneFilter)); - } - - @JmeThread - private void addFilterImpl(@NotNull final SceneFilter sceneFilter) { - final FilterPostProcessor postProcessor = EditorUtil.getGlobalFilterPostProcessor(); - postProcessor.addFilter(sceneFilter.get()); - } - - /** - * Remove a scene filter. - * - * @param sceneFilter the scene filter. - */ - @FromAnyThread - public void removeFilter(@NotNull final SceneFilter sceneFilter) { - EXECUTOR_MANAGER.addJmeTask(() -> removeFilterImpl(sceneFilter)); - } - - @JmeThread - private void removeFilterImpl(@NotNull final SceneFilter sceneFilter) { - final FilterPostProcessor postProcessor = EditorUtil.getGlobalFilterPostProcessor(); - postProcessor.removeFilter(sceneFilter.get()); - } - - /** - * @return true if need to show light models. - */ - @JmeThread - private boolean isLightShowed() { - return lightShowed; - } - - /** - * @param lightShowed true if need to show light models. - */ - @JmeThread - private void setLightShowed(final boolean lightShowed) { - this.lightShowed = lightShowed; - } - - /** - * @return true if need to show audio models. - */ - @JmeThread - private boolean isAudioShowed() { - return audioShowed; - } - - /** - * @param audioShowed true if need to show audio models. - */ - @JmeThread - private void setAudioShowed(final boolean audioShowed) { - this.audioShowed = audioShowed; - } - - /** - * Change light showing. - * - * @param showed the showed - */ - @FromAnyThread - public void updateLightShowed(final boolean showed) { - EXECUTOR_MANAGER.addJmeTask(() -> updateLightShowedImpl(showed)); - } - - /** - * The process to change light showing. - */ - @JmeThread - private void updateLightShowedImpl(final boolean showed) { - - if (showed == isLightShowed()) { - return; - } - - final Node lightNode = getLightNode(); - final Node modelNode = getModelNode(); - - if (showed) { - modelNode.attachChild(lightNode); - } else { - modelNode.detachChild(lightNode); - } - - setLightShowed(showed); - } - - /** - * Change audio showing. - * - * @param showed the showed - */ - @FromAnyThread - public void updateAudioShowed(final boolean showed) { - EXECUTOR_MANAGER.addJmeTask(() -> updateAudioShowedImpl(showed)); - } - - /** - * The process to change audio showing. - */ - @JmeThread - private void updateAudioShowedImpl(final boolean showed) { - - if (showed == isAudioShowed()) { - return; - } - - final Node audioNode = getAudioNode(); - final Node modelNode = getModelNode(); - - if (showed) { - modelNode.attachChild(audioNode); - } else { - modelNode.detachChild(audioNode); - } - - setAudioShowed(showed); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java deleted file mode 100644 index cd3fe3f5..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ss.editor.part3d.editor.impl.scene.handler; - -import com.jme3.scene.Spatial; -import com.ss.editor.extension.util.JmbExtUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The handler to updated positions for physics controls on spatial transformations. - * - * @author JavaSaBr - */ -public class PhysicsControlTransformationHandler implements Consumer { - - @Override - public void accept(@NotNull final Spatial spatial) { - JmbExtUtils.resetPhysicsControlPositions(spatial); - } -} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java deleted file mode 100644 index e49f63a9..00000000 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ss.editor.part3d.editor.impl.scene.handler; - -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.bullet.objects.PhysicsRigidBody; -import com.jme3.scene.Spatial; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The handler to reactivate enabled physics controls during transforming spatial. - * - * @author JavaSaBr - */ -public class ReactivatePhysicsControlsTransformationHandler implements Consumer { - - @Override - public void accept(@NotNull final Spatial spatial) { - NodeUtils.children(spatial) - .flatMap(ControlUtils::controls) - .filter(RigidBodyControl.class::isInstance) - .map(RigidBodyControl.class::cast) - .filter(RigidBodyControl::isEnabled) - .filter(control -> Float.compare(control.getMass(), 0.0F) != 0) - .filter(control -> !control.isActive()) - .forEach(PhysicsRigidBody::activate); - } -} diff --git a/src/main/java/com/ss/editor/plugin/EditorPlugin.java b/src/main/java/com/ss/editor/plugin/EditorPlugin.java deleted file mode 100644 index 05f3f012..00000000 --- a/src/main/java/com/ss/editor/plugin/EditorPlugin.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.ss.editor.plugin; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.file.converter.FileConverterRegistry; -import com.ss.editor.manager.FileIconManager; -import com.ss.editor.plugin.api.settings.SettingsProviderRegistry; -import com.ss.editor.ui.component.asset.tree.AssetTreeContextMenuFillerRegistry; -import com.ss.editor.ui.component.creator.FileCreatorRegistry; -import com.ss.editor.ui.component.editor.EditorRegistry; -import com.ss.editor.ui.component.painting.PaintingComponentRegistry; -import com.ss.editor.ui.control.property.builder.PropertyBuilderRegistry; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactoryRegistry; -import com.ss.editor.ui.css.CssRegistry; -import com.ss.editor.ui.preview.FilePreviewFactoryRegistry; -import com.ss.rlib.common.plugin.PluginContainer; -import com.ss.rlib.common.plugin.PluginSystem; -import com.ss.rlib.common.plugin.impl.BasePlugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.net.URL; - -/** - * The base implementation of a plugin for this editor. - * - * @author JavaSaBr - */ -public class EditorPlugin extends BasePlugin { - - public EditorPlugin(@NotNull PluginContainer pluginContainer) { - super(pluginContainer); - } - - /** - * Register this plugin's own CSS files. - * - * @param registry the CSS registry. - */ - @FromAnyThread - public void register(@NotNull CssRegistry registry) { - } - - /** - * Register this plugin's own file creators. - * - * @param registry the file creator registry. - */ - @FromAnyThread - public void register(@NotNull FileCreatorRegistry registry) { - } - - /** - * Register this plugin's own file editors. - * - * @param registry the file creator registry. - */ - @FromAnyThread - public void register(@NotNull EditorRegistry registry) { - } - - /** - * Register this plugin's own file icon finders. - * - * @param iconManager the icon manager. - */ - @FromAnyThread - public void register(@NotNull FileIconManager iconManager) { - } - - /** - * Register this plugin's own file converters. - * - * @param registry the converters registry. - */ - @FromAnyThread - public void register(@NotNull FileConverterRegistry registry) { - } - - /** - * Register this plugin's own asset tree context menu fillers. - * - * @param registry the menu fillers registry. - */ - @FromAnyThread - public void register(@NotNull AssetTreeContextMenuFillerRegistry registry) { - } - - /** - * Register this plugin's own tree node factories. - * - * @param registry the registry of tree node factories. - */ - @FromAnyThread - public void register(@NotNull TreeNodeFactoryRegistry registry) { - } - - /** - * Register this plugin's own property builders. - * - * @param registry the registry of property builders. - */ - @FromAnyThread - public void register(@NotNull PropertyBuilderRegistry registry) { - } - - /** - * Register this plugin's own file preview factories. - * - * @param registry the registry of file preview factories. - */ - @FromAnyThread - public void register(@NotNull FilePreviewFactoryRegistry registry) { - } - - /** - * Register this plugin's own settings providers. - * - * @param registry the registry of settings providers. - */ - @FxThread - public void register(@NotNull SettingsProviderRegistry registry) { - } - - /** - * Register this plugin's own painting component's constructors. - * - * @param registry the registry of painting component's constructors. - */ - @FxThread - public void register(@NotNull PaintingComponentRegistry registry) { - } - - /** - * Do some things before when jME context will be created. - * - * @param pluginSystem the plugin system. - */ - @JmeThread - public void onBeforeCreateJmeContext(@NotNull PluginSystem pluginSystem) { - } - - /** - * Do some things after when jME context was created. - * - * @param pluginSystem the plugin system. - */ - @JmeThread - public void onAfterCreateJmeContext(@NotNull PluginSystem pluginSystem) { - } - - /** - * Do some things before when JavaFX context will be created. - * - * @param pluginSystem the plugin system. - */ - @FxThread - public void onBeforeCreateJavaFxContext(@NotNull PluginSystem pluginSystem) { - } - - /** - * Do some things after when JavaFX context was created. - * - * @param pluginSystem the plugin system. - */ - @FxThread - public void onAfterCreateJavaFxContext(@NotNull PluginSystem pluginSystem) { - } - - /** - * Do some things before when the editor is ready to work. - * - * @param pluginSystem the plugin system. - */ - @FxThread - public void onFinishLoading(@NotNull PluginSystem pluginSystem) { - } - - @Override - @FromAnyThread - public @NotNull PluginContainer getContainer() { - return super.getContainer(); - } - - /** - * Get the URL to a home page of this plugin. - * - * @return the URL of a home page of this plugin or null. - */ - @FromAnyThread - public @Nullable URL getHomePageUrl() { - return null; - } - - /** - * Get the HTML presentation of plugin's dependencies as gradle dependencies. - * - * @return the HTML presentation of plugin's dependencies as gradle dependencies. - */ - @FromAnyThread - public @Nullable String getUsedGradleDependencies() { - return null; - } - - /** - * Get the HTML presentation of plugin's dependencies as maven dependencies. - * - * @return the HTML presentation of plugin's dependencies as maven dependencies. - */ - @FromAnyThread - public @Nullable String getUsedMavenDependencies() { - return null; - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/RenderFilterExtension.java b/src/main/java/com/ss/editor/plugin/api/RenderFilterExtension.java deleted file mode 100644 index dd2697a2..00000000 --- a/src/main/java/com/ss/editor/plugin/api/RenderFilterExtension.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.ss.editor.plugin.api; - -import com.jme3.post.Filter; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.ClassUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The class with some extensions to editor's render. - * - * @author JavaSaBr - */ -public class RenderFilterExtension { - - @NotNull - private static final RenderFilterExtension INSTANCE = new RenderFilterExtension(); - - @FromAnyThread - public static @NotNull RenderFilterExtension getInstance() { - return INSTANCE; - } - - /** - * The map filter to its refresh action. - */ - @NotNull - private final ObjectDictionary> refreshActions; - - /** - * The additional filters. - */ - @NotNull - private final Array filters; - - private RenderFilterExtension() { - this.filters = ArrayFactory.newArray(Filter.class); - this.refreshActions = DictionaryFactory.newObjectDictionary(); - } - - /** - * Register the new additional filter. - * - * @param filter the filter. - */ - @JmeThread - public void register(@NotNull Filter filter) { - this.filters.add(filter); - EditorUtil.getGlobalFilterPostProcessor() - .addFilter(filter); - } - - /** - * Set the handler to handle refresh events. - * - * @param filter the filter. - * @param handler the handler. - * @param the filter's type. - */ - @JmeThread - public void setOnRefresh(@NotNull T filter, @NotNull Consumer handler) { - - if (!filters.contains(filter)) { - throw new IllegalArgumentException("The filter " + filter + "isn't registered."); - } - - refreshActions.put(filter, handler); - } - - /** - * Refresh all filters. - */ - @JmeThread - public void refreshFilters() { - refreshActions.forEach((filter, consumer) -> { - var cast = ClassUtils.>unsafeCast(consumer); - cast.accept(filter); - }); - } - - @JmeThread - public void enableFilters() { - - } - - @JmeThread - public void disableFilters() { - - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditor.java b/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditor.java deleted file mode 100644 index 3d64048f..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import static com.ss.editor.ui.component.editor.FileEditorUtils.loadCameraState; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.editor.part3d.Advanced3DEditorPart; -import com.ss.editor.ui.component.editor.state.impl.Editor3DEditorState; - -/** - * The advanced implementation of 3D editor. - * - * @author JavaSaBr - */ -public abstract class Advanced3DFileEditor - extends Base3DFileEditor { - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - final S editorState = getEditorState(); - if (editorState != null) { - loadCameraState(editorState, getEditor3DPart()); - } - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java b/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java deleted file mode 100644 index 20d005c7..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.editor.part3d.Advanced3DEditorPart; -import com.ss.editor.ui.component.editor.state.impl.Editor3DWithEditorToolEditorState; -import com.ss.editor.ui.component.split.pane.EditorToolSplitPane; -import com.ss.editor.ui.component.tab.EditorToolComponent; -import com.ss.editor.ui.component.tab.ScrollableEditorToolComponent; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import javafx.event.Event; -import javafx.scene.input.DragEvent; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The advanced implementation of 3D editor with a right tool. - * - * @author JavaSaBr - */ -public abstract class Advanced3DFileEditorWithRightTool - extends Advanced3DFileEditor { - - /** - * The main split container. - */ - @Nullable - private EditorToolSplitPane mainSplitContainer; - - /** - * Editor tool component. - */ - @Nullable - private ScrollableEditorToolComponent editorToolComponent; - - /** - * The pane of editor area. - */ - @Nullable - private StackPane editorAreaPane; - - /** - * The pane of 3D editor area. - */ - @Nullable - private BorderPane editor3DArea; - - @Override - @FxThread - protected void createContent(@NotNull final StackPane root) { - createEditorAreaPane(); - - mainSplitContainer = new EditorToolSplitPane(EditorUtil.getFxScene(), root); - - editorToolComponent = new ScrollableEditorToolComponent(mainSplitContainer, 1); - editorToolComponent.prefHeightProperty().bind(root.heightProperty()); - - createToolComponents(editorToolComponent, root); - - editorToolComponent.addChangeListener((observable, oldValue, newValue) -> processChangeTool(oldValue, newValue)); - editorToolComponent.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { - final S editorState = getEditorState(); - if (editorState != null) { - editorState.setOpenedTool(newValue.intValue()); - } - }); - - mainSplitContainer.initFor(editorToolComponent, getEditorAreaPane()); - - FXUtils.addToPane(mainSplitContainer, root); - FXUtils.addClassTo(mainSplitContainer, CssClasses.FILE_EDITOR_MAIN_SPLIT_PANE); - } - - /** - * Create editor area pane. - */ - @FxThread - protected void createEditorAreaPane() { - - editorAreaPane = new StackPane(); - editorAreaPane.setOnDragOver(this::handleDragOverEvent); - editorAreaPane.setOnDragDropped(this::handleDragDroppedEvent); - - editor3DArea = new BorderPane(); - editor3DArea.setOnMousePressed(event -> editor3DArea.requestFocus()); - editor3DArea.setOnKeyReleased(Event::consume); - editor3DArea.setOnKeyPressed(Event::consume); - - FXUtils.addToPane(editor3DArea, editorAreaPane); - FXUtils.addClassTo(editorAreaPane, CssClasses.FILE_EDITOR_EDITOR_AREA); - } - - /** - * Process change tool. - * - * @param oldValue the old value - * @param newValue the new value - */ - @FxThread - protected void processChangeTool(@Nullable final Number oldValue, @NotNull final Number newValue) { - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - final S editorState = getEditorState(); - if (editorState == null) { - return; - } - - getEditorToolComponent().getSelectionModel() - .select(editorState.getOpenedTool()); - - getMainSplitContainer().updateFor(editorState); - } - - @Override - @FxThread - public @Nullable BorderPane get3DArea() { - return editor3DArea; - } - - /** - * Get the pane of editor area. - * - * @return the pane of editor area. - */ - @FxThread - protected @NotNull StackPane getEditorAreaPane() { - return notNull(editorAreaPane); - } - - /** - * Get the editor tool component. - * - * @return the editor tool component. - */ - @FxThread - protected @NotNull ScrollableEditorToolComponent getEditorToolComponent() { - return notNull(editorToolComponent); - } - - /** - * Get the main split container. - * - * @return the main split container. - */ - @FxThread - protected @NotNull EditorToolSplitPane getMainSplitContainer() { - return notNull(mainSplitContainer); - } - - /** - * Create and add tool components to the container. - * - * @param container the tool container. - * @param root the root. - */ - @FxThread - protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { - } - - /** - * Handle drag over events. - * - * @param dragEvent the drag event. - */ - @FxThread - protected void handleDragOverEvent(@NotNull final DragEvent dragEvent) { - } - - /** - * Handle dropped events. - * - * @param dragEvent the drop event. - */ - @FxThread - protected void handleDragDroppedEvent(@NotNull final DragEvent dragEvent) { - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithSplitRightTool.java b/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithSplitRightTool.java deleted file mode 100644 index fbb272c2..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithSplitRightTool.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.editor.part3d.Advanced3DEditorPart; -import com.ss.editor.ui.component.editor.state.impl.Editor3DWithEditorToolEditorState; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.Node; -import javafx.scene.control.SplitPane; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; - -/** - * The advanced implementation of 3D editor with a split right tool. - * - * @author JavaSaBr - */ -public abstract class Advanced3DFileEditorWithSplitRightTool extends - Advanced3DFileEditorWithRightTool { - - /** - * Build split component. - * - * @param first the first component. - * @param second the second component. - * @param root the root. - * @return the result component. - */ - @FxThread - protected Region buildSplitComponent(@NotNull final Node first, @NotNull final Node second, - @NotNull final StackPane root) { - - final SplitPane splitPane = new SplitPane(first, second); - splitPane.prefHeightProperty().bind(root.heightProperty()); - splitPane.prefWidthProperty().bind(root.widthProperty()); - - root.heightProperty().addListener((observableValue, oldValue, newValue) -> calcVSplitSize(splitPane)); - - FXUtils.addClassTo(splitPane, CssClasses.FILE_EDITOR_TOOL_SPLIT_PANE); - - return splitPane; - } - - /** - * Calc height of vertical split pane. - * - * @param splitPane the split pane - */ - @FxThread - protected void calcVSplitSize(@NotNull final SplitPane splitPane) { - splitPane.setDividerPosition(0, 0.3); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/Base3DFileEditor.java b/src/main/java/com/ss/editor/plugin/api/editor/Base3DFileEditor.java deleted file mode 100644 index 3484d4cc..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/Base3DFileEditor.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.part3d.editor.impl.AbstractEditor3DPart; -import com.ss.editor.ui.component.editor.state.impl.Editor3DEditorState; -import javafx.event.Event; -import javafx.geometry.Point2D; -import javafx.scene.input.MouseEvent; -import javafx.scene.input.ScrollEvent; -import javafx.scene.layout.Pane; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor} with 3D scene. - * - * @author JavaSaBr - */ -public abstract class Base3DFileEditor extends - BaseFileEditor { - - /** - * The 3D part of this editor. - */ - @NotNull - private final T editor3DPart; - - public Base3DFileEditor() { - this.editor3DPart = create3DEditorPart(); - addEditor3DPart(editor3DPart); - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - } - - @Override - protected boolean needListenEventsFromPage() { - return false; - } - - /** - * Create 3D part of this editor. - * - * @return the 3D part. - */ - @FxThread - protected abstract @NotNull T create3DEditorPart(); - - /** - * Get the 3D part of this editor. - * - * @return the 3D part of this editor. - */ - @FromAnyThread - protected @NotNull T getEditor3DPart() { - return editor3DPart; - } - - @Override - @FxThread - public void notifyChangedCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, - final float cameraSpeed) { - super.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed); - - final S editorState = getEditorState(); - if (editorState == null) return; - - editorState.setCameraHRotation(hRotation); - editorState.setCameraVRotation(vRotation); - editorState.setCameraTDistance(targetDistance); - editorState.setCameraLocation(cameraLocation); - editorState.setCameraSpeed(cameraSpeed); - } - - @Override - @FxThread - public boolean isInside(final double sceneX, final double sceneY, @NotNull final Class eventType) { - - final Pane editorPage = getPage(); - final Pane editor3DPage = get3DArea() == null ? editorPage : get3DArea(); - - final boolean only3D = eventType.isAssignableFrom(MouseEvent.class) || - eventType.isAssignableFrom(ScrollEvent.class); - - final Pane page = only3D ? editor3DPage : editorPage; - - final Point2D point2D = page.sceneToLocal(sceneX, sceneY); - return page.contains(point2D); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditor.java b/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditor.java deleted file mode 100644 index b6688e60..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditor.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.WorkspaceManager; -import com.ss.editor.model.undo.EditorOperation; -import com.ss.editor.model.undo.EditorOperationControl; -import com.ss.editor.model.undo.UndoableEditor; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.workspace.Workspace; -import com.ss.editor.ui.component.editor.impl.AbstractFileEditor; -import com.ss.editor.ui.component.editor.state.EditorState; -import javafx.event.Event; -import javafx.scene.input.KeyCode; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; - -/** - * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor}. - * - * @author JavaSaBr - */ -public abstract class BaseFileEditor extends AbstractFileEditor implements - UndoableEditor, ChangeConsumer { - - /** - * The operation control. - */ - @NotNull - private final EditorOperationControl operationControl; - - /** - * The changes counter. - */ - @NotNull - private final AtomicInteger changeCounter; - - /** - * The state of this editor. - */ - @Nullable - protected S editorState; - - /** - * The flag for ignoring listeners. - */ - private boolean ignoreListeners; - - protected BaseFileEditor() { - this.operationControl = createOperationControl(); - this.changeCounter = new AtomicInteger(); - } - - /** - * Create an editor operation control. - * - * @return the editor operation control. - */ - @FxThread - protected @NotNull EditorOperationControl createOperationControl() { - return new EditorOperationControl(this); - } - - @Override - @FromAnyThread - public void execute(@NotNull final EditorOperation operation) { - operationControl.execute(operation); - } - - @FxThread - @Override - protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final boolean isPressed, - final boolean isControlDown, final boolean isShiftDown, - final boolean isButtonMiddleDown) { - - if (isPressed && isControlDown && keyCode == KeyCode.Z) { - undo(); - return true; - } else if (isPressed && isControlDown && isShiftDown && keyCode == KeyCode.Z) { - redo(); - return true; - } else if (isPressed && isControlDown && keyCode == KeyCode.Y) { - redo(); - return true; - } - - return super.handleKeyActionImpl(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); - } - - @Override - @FxThread - public void incrementChange() { - final int result = changeCounter.incrementAndGet(); - setDirty(result != 0); - } - - @Override - @FxThread - public void decrementChange() { - final int result = changeCounter.decrementAndGet(); - setDirty(result != 0); - } - - @Override - @FromAnyThread - public void redo() { - operationControl.redo(); - } - - @Override - @FromAnyThread - public void undo() { - operationControl.undo(); - } - - /** - * Get the editor operation control. - * - * @return the editor operation control. - */ - @FromAnyThread - protected @NotNull EditorOperationControl getOperationControl() { - return operationControl; - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - - try { - doOpenFile(file); - } catch (final IOException e) { - throw new RuntimeException(e); - } - - EXECUTOR_MANAGER.addFxTask(this::loadState); - } - - /** - * Loading a state of this editor. - */ - @FxThread - protected void loadState() { - - final Supplier stateFactory = getEditorStateFactory(); - if (stateFactory == null) { - return; - } - - final WorkspaceManager workspaceManager = WorkspaceManager.getInstance(); - final Workspace currentWorkspace = notNull(workspaceManager.getCurrentWorkspace()); - - editorState = currentWorkspace.getEditorState(getEditFile(), stateFactory); - } - - /** - * Get the factory to make an editor state. - * - * @return the factory to make an editor state. - */ - @FxThread - protected @Nullable Supplier getEditorStateFactory() { - return null; - } - - /** - * Do main activities to open the file. - * - * @param file the file to open. - * @throws IOException if was some problem with writing to the file. - */ - @FxThread - protected void doOpenFile(@NotNull final Path file) throws IOException { - } - - /** - * @param ignoreListeners the flag for ignoring listeners. - */ - @FromAnyThread - protected void setIgnoreListeners(final boolean ignoreListeners) { - this.ignoreListeners = ignoreListeners; - } - - /** - * @return the flag for ignoring listeners. - */ - @FromAnyThread - protected boolean isIgnoreListeners() { - return ignoreListeners; - } - - @Override - @FxThread - protected @NotNull StackPane createRoot() { - return new StackPane(); - } - - @Override - @FxThread - public @Nullable BorderPane get3DArea() { - return null; - } - - /** - * Get the editor state. - * - * @return the editor state. - */ - @FromAnyThread - protected @Nullable S getEditorState() { - return editorState; - } - - @Override - @FxThread - public boolean isInside(final double sceneX, final double sceneY, @NotNull final Class eventType) { - return false; - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithRightTool.java b/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithRightTool.java deleted file mode 100644 index aa7b74e8..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithRightTool.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.impl.EditorWithEditorToolEditorState; -import com.ss.editor.ui.component.split.pane.EditorToolSplitPane; -import com.ss.editor.ui.component.tab.EditorToolComponent; -import com.ss.editor.ui.component.tab.ScrollableEditorToolComponent; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.input.DragEvent; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of a file editor without 3D part and with right tool panel. - * - * @author JavaSaBr - */ -public abstract class BaseFileEditorWithRightTool extends BaseFileEditor { - - /** - * The main split container. - */ - @Nullable - private EditorToolSplitPane mainSplitContainer; - - /** - * Editor tool component. - */ - @Nullable - private ScrollableEditorToolComponent editorToolComponent; - - /** - * The pane of editor area. - */ - @Nullable - private StackPane editorAreaPane; - - @Override - @FxThread - protected void createContent(@NotNull final StackPane root) { - createEditorAreaPane(); - - mainSplitContainer = new EditorToolSplitPane(EditorUtil.getFxScene(), root); - - editorToolComponent = new ScrollableEditorToolComponent(mainSplitContainer, 1); - editorToolComponent.prefHeightProperty().bind(root.heightProperty()); - - createToolComponents(editorToolComponent, root); - - editorToolComponent.addChangeListener((observable, oldValue, newValue) -> processChangeTool(oldValue, newValue)); - editorToolComponent.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { - final S editorState = getEditorState(); - if (editorState != null) editorState.setOpenedTool(newValue.intValue()); - }); - - mainSplitContainer.initFor(editorToolComponent, getEditorAreaPane()); - - FXUtils.addToPane(mainSplitContainer, root); - FXUtils.addClassTo(mainSplitContainer, CssClasses.FILE_EDITOR_MAIN_SPLIT_PANE); - } - - /** - * Create editor area pane. - */ - @FxThread - protected void createEditorAreaPane() { - - editorAreaPane = new StackPane(); - editorAreaPane.setOnDragOver(this::handleDragOverEvent); - editorAreaPane.setOnDragDropped(this::handleDragDroppedEvent); - - FXUtils.addClassTo(editorAreaPane, CssClasses.FILE_EDITOR_EDITOR_AREA); - } - - /** - * Process change tool. - * - * @param oldValue the old value - * @param newValue the new value - */ - @FxThread - protected void processChangeTool(@Nullable final Number oldValue, @NotNull final Number newValue) { - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - final S editorState = getEditorState(); - if (editorState == null) { - return; - } - - editorToolComponent.getSelectionModel().select(editorState.getOpenedTool()); - mainSplitContainer.updateFor(editorState); - } - - /** - * @return the pane of editor area. - */ - @FxThread - protected @NotNull StackPane getEditorAreaPane() { - return notNull(editorAreaPane); - } - - /** - * Create and add tool components to the container. - * - * @param container the tool container. - * @param root the root. - */ - @FxThread - protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { - } - - /** - * Handle drag over events. - * - * @param dragEvent the drag event. - */ - @FxThread - protected void handleDragOverEvent(@NotNull final DragEvent dragEvent) { - } - - /** - * Handle dropped events. - * - * @param dragEvent the drop event. - */ - @FxThread - protected void handleDragDroppedEvent(@NotNull final DragEvent dragEvent) { - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithSplitRightTool.java b/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithSplitRightTool.java deleted file mode 100644 index 69fad2f7..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithSplitRightTool.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.impl.EditorWithEditorToolEditorState; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.Node; -import javafx.scene.control.SplitPane; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; - -/** - * The base implementation of a file editor without 3D part and with right split tool panel. - * - * @author JavaSaBr - */ -public abstract class BaseFileEditorWithSplitRightTool extends - BaseFileEditorWithRightTool { - - /** - * Build split component. - * - * @param first the first component. - * @param second the second component. - * @param root the root. - * @return the result component. - */ - @FxThread - protected Region buildSplitComponent(@NotNull final Node first, @NotNull final Node second, - @NotNull final StackPane root) { - - final SplitPane splitPane = new SplitPane(first, second); - splitPane.prefHeightProperty().bind(root.heightProperty()); - splitPane.prefWidthProperty().bind(root.widthProperty()); - - root.heightProperty().addListener((observableValue, oldValue, newValue) -> calcVSplitSize(splitPane)); - - FXUtils.addClassTo(splitPane, CssClasses.FILE_EDITOR_TOOL_SPLIT_PANE); - - return splitPane; - } - - /** - * Calc height of vertical split pane. - * - * @param splitPane the split pane - */ - @FxThread - protected void calcVSplitSize(@NotNull final SplitPane splitPane) { - splitPane.setDividerPosition(0, 0.3); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithoutState.java b/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithoutState.java deleted file mode 100644 index 093347ca..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/BaseFileEditorWithoutState.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.ss.editor.plugin.api.editor; - -import com.ss.editor.ui.component.editor.state.impl.VoidEditorState; - -/** - * The base implementation of {@link com.ss.editor.ui.component.editor.FileEditor} without - * {@link com.ss.editor.ui.component.editor.state.EditorState}. - * - * @author JavaSaBr - */ -public abstract class BaseFileEditorWithoutState extends BaseFileEditor { -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialEditor3DPart.java b/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialEditor3DPart.java deleted file mode 100644 index d39831e9..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialEditor3DPart.java +++ /dev/null @@ -1,418 +0,0 @@ -package com.ss.editor.plugin.api.editor.material; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetNotFoundException; -import com.jme3.input.InputManager; -import com.jme3.input.KeyInput; -import com.jme3.input.controls.KeyTrigger; -import com.jme3.light.DirectionalLight; -import com.jme3.material.Material; -import com.jme3.math.Vector3f; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.RendererException; -import com.jme3.renderer.queue.RenderQueue.Bucket; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.jme3.scene.shape.Box; -import com.jme3.scene.shape.Quad; -import com.jme3.scene.shape.Sphere; -import com.ss.editor.EditorThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.EditorCamera; -import com.ss.editor.util.TangentGenerator; -import com.ss.editor.plugin.api.editor.part3d.AdvancedPbrWithStudioSky3DEditorPart; -import com.ss.editor.ui.component.editor.impl.material.MaterialFileEditor; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.function.BooleanFloatConsumer; -import com.ss.rlib.common.geom.util.AngleUtils; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.scene.input.KeyCode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation the 3D part of the {@link MaterialFileEditor}. - * - * @author JavaSaBr - */ -public class BaseMaterialEditor3DPart extends - AdvancedPbrWithStudioSky3DEditorPart { - - @NotNull - private static final Vector3f QUAD_OFFSET = new Vector3f(0, -2, 2); - - @NotNull - private static final Vector3f LIGHT_DIRECTION = new Vector3f(0.007654993F, 0.39636374F, 0.9180617F).negate(); - - private static final float H_ROTATION = AngleUtils.degreeToRadians(75); - private static final float V_ROTATION = AngleUtils.degreeToRadians(25); - - @NotNull - private static final String KEY_C = "SSEditor.materialEditorState.C"; - - @NotNull - private static final String KEY_S = "SSEditor.materialEditorState.S"; - - @NotNull - private static final String KEY_P = "SSEditor.materialEditorState.P"; - - @NotNull - private static final String KEY_L = "SSEditor.materialEditorState.L"; - - static { - TRIGGERS.put(KEY_C, new KeyTrigger(KeyInput.KEY_C)); - TRIGGERS.put(KEY_S, new KeyTrigger(KeyInput.KEY_S)); - TRIGGERS.put(KEY_P, new KeyTrigger(KeyInput.KEY_P)); - TRIGGERS.put(KEY_L, new KeyTrigger(KeyInput.KEY_L)); - } - - /** - * The test box. - */ - @NotNull - private final Geometry testBox; - - /** - * The test sphere. - */ - @NotNull - private final Geometry testSphere; - - /** - * The test quad. - */ - @NotNull - private final Geometry testQuad; - - /** - * The current model mode. - */ - @Nullable - private ModelType currentModelType; - - /** - * The flag of enabling light. - */ - private boolean lightEnabled; - - public BaseMaterialEditor3DPart(@NotNull final T fileEditor) { - super(fileEditor); - this.testBox = new Geometry("Box", new Box(2, 2, 2)); - this.testSphere = new Geometry("Sphere", new Sphere(30, 30, 2)); - this.testQuad = new Geometry("Quad", new Quad(4, 4)); - this.testQuad.setLocalTranslation(QUAD_OFFSET); - this.lightEnabled = MaterialFileEditor.DEFAULT_LIGHT_ENABLED; - - TangentGenerator.useMikktspaceGenerator(testBox); - TangentGenerator.useMikktspaceGenerator(testSphere); - TangentGenerator.useMikktspaceGenerator(testQuad); - - final DirectionalLight light = notNull(getLightForCamera()); - light.setDirection(LIGHT_DIRECTION); - - final EditorCamera editorCamera = notNull(getEditorCamera()); - editorCamera.setDefaultHorizontalRotation(H_ROTATION); - editorCamera.setDefaultVerticalRotation(V_ROTATION); - - getModelNode().attachChild(getNodeForCamera()); - } - - @Override - @JmeThread - protected void registerActionHandlers(@NotNull final ObjectDictionary actionHandlers) { - super.registerActionHandlers(actionHandlers); - - final T fileEditor = getFileEditor(); - - actionHandlers.put(KEY_S, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.S, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - - actionHandlers.put(KEY_C, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.C, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - - actionHandlers.put(KEY_P, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.P, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - - actionHandlers.put(KEY_L, (isPressed, tpf) -> - fileEditor.handleKeyAction(KeyCode.L, isPressed, isControlDown(), isShiftDown(), isButtonMiddleDown())); - } - - @Override - @JmeThread - protected void registerActionListener(@NotNull final InputManager inputManager) { - super.registerActionListener(inputManager); - inputManager.addListener(actionListener, KEY_S, KEY_C, KEY_P, KEY_L); - } - - /** - * Get the test box. - * - * @return the test box. - */ - @JmeThread - protected @NotNull Geometry getTestBox() { - return testBox; - } - - /** - * Get the test quad. - * - * @return the test quad. - */ - @JmeThread - protected @NotNull Geometry getTestQuad() { - return testQuad; - } - - /** - * Get the test sphere. - * - * @return the test sphere. - */ - @JmeThread - protected @NotNull Geometry getTestSphere() { - return testSphere; - } - - /** - * Update the {@link Material}. - * - * @param material the material - */ - @FromAnyThread - public void updateMaterial(@NotNull final Material material) { - EXECUTOR_MANAGER.addJmeTask(() -> updateMaterialImpl(material)); - } - - /** - * Update the {@link Material} in the {@link EditorThread}. - * - * @param material the new material. - */ - @JmeThread - protected void updateMaterialImpl(@NotNull final Material material) { - - final Geometry testBox = getTestBox(); - testBox.setMaterial(material); - - final Geometry testQuad = getTestQuad(); - testQuad.setMaterial(material); - - final Geometry testSphere = getTestSphere(); - testSphere.setMaterial(material); - - final RenderManager renderManager = EditorUtil.getRenderManager(); - try { - renderManager.preloadScene(testBox); - } catch (final RendererException | AssetNotFoundException | UnsupportedOperationException e) { - handleMaterialException(e); - testBox.setMaterial(EditorUtil.getDefaultMaterial()); - testQuad.setMaterial(EditorUtil.getDefaultMaterial()); - testSphere.setMaterial(EditorUtil.getDefaultMaterial()); - } - } - - /** - * Handle the material exception. - * - * @param exception the exception. - */ - @JmeThread - protected void handleMaterialException(@NotNull final RuntimeException exception) { - EditorUtil.handleException(LOGGER, this, exception); - } - - /** - * Change the {@link ModelType}. - * - * @param modelType the model type - */ - @FromAnyThread - public void changeMode(@NotNull final ModelType modelType) { - EXECUTOR_MANAGER.addJmeTask(() -> changeModeImpl(modelType)); - } - - /** - * Change the {@link ModelType} in the {@link EditorThread}. - * - * @param modelType the new model type. - */ - @JmeThread - protected void changeModeImpl(@NotNull final ModelType modelType) { - - final Node modelNode = getModelNode(); - modelNode.detachAllChildren(); - - switch (modelType) { - case BOX: { - modelNode.attachChild(getTestBox()); - break; - } - case QUAD: { - modelNode.attachChild(getTestQuad()); - break; - } - case SPHERE: { - modelNode.attachChild(getTestSphere()); - break; - } - } - - setCurrentModelType(modelType); - } - - /** - * Change the {@link Bucket}. - * - * @param bucket the bucket - */ - @FromAnyThread - public void changeBucketType(@NotNull final Bucket bucket) { - EXECUTOR_MANAGER.addJmeTask(() -> changeBucketTypeImpl(bucket)); - } - - /** - * Change the {@link Bucket} in the {@link EditorThread}. - * - * @param bucket the new bucket. - */ - @JmeThread - protected void changeBucketTypeImpl(@NotNull final Bucket bucket) { - - final Geometry testQuad = getTestQuad(); - testQuad.setQueueBucket(bucket); - - final Geometry testSphere = getTestSphere(); - testSphere.setQueueBucket(bucket); - - final Geometry testBox = getTestBox(); - testBox.setQueueBucket(bucket); - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - changeModeImpl(getCurrentModelType()); - } - - @Override - @JmeThread - protected boolean needMovableCamera() { - return false; - } - - @Override - @JmeThread - protected boolean needEditorCamera() { - return true; - } - - @Override - @JmeThread - protected boolean needLightForCamera() { - return true; - } - - /** - * @return the current model mode. - */ - @JmeThread - protected @NotNull ModelType getCurrentModelType() { - return notNull(currentModelType); - } - - /** - * @param currentModelType the current model mode. - */ - @JmeThread - protected void setCurrentModelType(@NotNull final ModelType currentModelType) { - this.currentModelType = currentModelType; - } - - /** - * @return true if the light is enabled. - */ - @JmeThread - protected boolean isLightEnabled() { - return lightEnabled; - } - - /** - * @param lightEnabled true if the light is enabled. - */ - @JmeThread - protected void setLightEnabled(final boolean lightEnabled) { - this.lightEnabled = lightEnabled; - } - - /** - * Update the light in the scene. - * - * @param enabled the enabled - */ - @FromAnyThread - public void updateLightEnabled(final boolean enabled) { - EXECUTOR_MANAGER.addJmeTask(() -> updateLightEnabledImpl(enabled)); - } - - /** - * Update the light in the scene in the {@link EditorThread}. - * - * @param enabled true if light should be enabled. - */ - @JmeThread - protected void updateLightEnabledImpl(final boolean enabled) { - if (enabled == isLightEnabled()) return; - - final DirectionalLight light = getLightForCamera(); - final Node stateNode = getStateNode(); - - if (enabled) { - stateNode.addLight(light); - } else { - stateNode.removeLight(light); - } - - setLightEnabled(enabled); - } - - @Override - @JmeThread - protected boolean needUpdateCameraLight() { - return false; - } - - /** - * The enum Model type. - */ - public enum ModelType { - /** - * Sphere model type. - */ - SPHERE, - /** - * Box model type. - */ - BOX, - /** - * Quad model type. - */ - QUAD; - - private static final ModelType[] VALUES = values(); - - /** - * Value of model type. - * - * @param index the index - * @return the model type - */ - public static ModelType valueOf(final int index) { - return VALUES[index]; - } - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java b/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java deleted file mode 100644 index 00ee97cd..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java +++ /dev/null @@ -1,422 +0,0 @@ -package com.ss.editor.plugin.api.editor.material; - -import static com.jme3.renderer.queue.RenderQueue.Bucket.Inherit; -import static com.jme3.renderer.queue.RenderQueue.Bucket.values; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static javafx.collections.FXCollections.observableArrayList; -import com.jme3.material.Material; -import com.jme3.renderer.queue.RenderQueue; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.plugin.api.editor.Advanced3DFileEditorWithSplitRightTool; -import com.ss.editor.plugin.api.editor.material.BaseMaterialEditor3DPart.ModelType; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.ui.component.editor.state.impl.EditorMaterialEditorState; -import com.ss.editor.ui.component.tab.EditorToolComponent; -import com.ss.editor.ui.control.property.PropertyEditor; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.collections.ObservableList; -import javafx.scene.control.*; -import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCode; -import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -/** - * The implementation of the Editor to edit materials. - * - * @author JavaSaBr - */ -public abstract class BaseMaterialFileEditor extends - Advanced3DFileEditorWithSplitRightTool { - - /** - * The default state of editor light. - */ - public static final boolean DEFAULT_LIGHT_ENABLED = true; - - /** - * The list of available bucket types. - */ - @NotNull - protected static final ObservableList BUCKETS = observableArrayList(values()); - - /** - * The settings tree. - */ - @Nullable - private NodeTree settingsTree; - - /** - * The property editor. - */ - @Nullable - private PropertyEditor propertyEditor; - - /** - * The button to use a cube. - */ - @Nullable - private ToggleButton cubeButton; - - /** - * The button to use a sphere. - */ - @Nullable - private ToggleButton sphereButton; - - /** - * The button to use a plane. - */ - @Nullable - private ToggleButton planeButton; - - /** - * The button to use a light. - */ - @Nullable - private ToggleButton lightButton; - - /** - * The list of RenderQueue.Bucket. - */ - @Nullable - private ComboBox bucketComboBox; - - protected BaseMaterialFileEditor() { - super(); - } - - /** - * Get the change consumer. - * - * @return the change consumer. - */ - @FromAnyThread - protected C getChangeConsumer() { - return unsafeCast(this); - } - - @Override - @FxThread - protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final boolean isPressed, - final boolean isControlDown, final boolean isShiftDown, - final boolean isButtonMiddleDown) { - - if (isPressed && keyCode == KeyCode.C && !isControlDown && !isButtonMiddleDown) { - final ToggleButton cubeButton = getCubeButton(); - cubeButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.S && !isControlDown && !isButtonMiddleDown) { - final ToggleButton sphereButton = getSphereButton(); - sphereButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.P && !isControlDown && !isButtonMiddleDown) { - final ToggleButton planeButton = getPlaneButton(); - planeButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.L && !isControlDown && !isButtonMiddleDown) { - final ToggleButton lightButton = getLightButton(); - lightButton.setSelected(!lightButton.isSelected()); - return true; - } - - return super.handleKeyActionImpl(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); - } - - @Override - @FxThread - protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { - super.createToolComponents(container, root); - - settingsTree = new NodeTree<>(this::selectFromTree, getChangeConsumer(), SelectionMode.SINGLE); - propertyEditor = new PropertyEditor<>(getChangeConsumer()); - propertyEditor.prefHeightProperty().bind(root.heightProperty()); - - container.addComponent(buildSplitComponent(settingsTree, propertyEditor, root), getSettingsTreeToolName()); - - FXUtils.addClassTo(settingsTree.getTreeView(), CssClasses.TRANSPARENT_TREE_VIEW); - } - - /** - * Get the settings tree tool name. - * - * @return the settings tree tool name. - */ - @FromAnyThread - protected @NotNull String getSettingsTreeToolName() { - return Messages.MATERIAL_SETTINGS_MAIN; - } - - /** - * @return the settings tree. - */ - @FromAnyThread - protected @NotNull NodeTree getSettingsTree() { - return notNull(settingsTree); - } - - /** - * @return the property editor. - */ - @FromAnyThread - protected @NotNull PropertyEditor getPropertyEditor() { - return notNull(propertyEditor); - } - - /** - * Handle selected objects from tree. - * - * @param objects the selected objects. - */ - @FxThread - private void selectFromTree(@NotNull final Array objects) { - - final Object object = objects.first(); - - Object parent = null; - Object element; - - if (object instanceof TreeNode) { - final TreeNode treeNode = (TreeNode) object; - final TreeNode parentNode = treeNode.getParent(); - parent = parentNode == null ? null : parentNode.getElement(); - element = treeNode.getElement(); - } else { - element = object; - } - - getPropertyEditor().buildFor(element, parent); - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - switch (ModelType.valueOf(editorState.getModelType())) { - case BOX: - getCubeButton().setSelected(true); - break; - case SPHERE: - getSphereButton().setSelected(true); - break; - case QUAD: - getPlaneButton().setSelected(true); - break; - } - - getBucketComboBox().getSelectionModel().select(editorState.getBucketType()); - getLightButton().setSelected(editorState.isLightEnable()); - } - - @Override - @FxThread - protected @Nullable Supplier getEditorStateFactory() { - return EditorMaterialEditorState::new; - } - - @Override - @FxThread - protected void calcVSplitSize(@NotNull final SplitPane splitPane) { - splitPane.setDividerPosition(0, 0.2); - } - - @Override - @FxThread - protected boolean needToolbar() { - return true; - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - createActions(container); - - final Label bucketLabel = new Label(Messages.MATERIAL_FILE_EDITOR_BUCKET_TYPE_LABEL + ":"); - - bucketComboBox = new ComboBox<>(BUCKETS); - bucketComboBox.getSelectionModel().select(Inherit); - bucketComboBox.getSelectionModel() - .selectedItemProperty() - .addListener((observable, oldValue, newValue) -> changeBucketType(newValue)); - - FXUtils.addToPane(bucketLabel, container); - FXUtils.addToPane(bucketComboBox, container); - } - - /** - * Create actions on toolbar. - * - * @param container the container. - */ - @FxThread - protected void createActions(@NotNull final HBox container) { - - cubeButton = new ToggleButton(); - cubeButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_CUBE + " (C)")); - cubeButton.setGraphic(new ImageView(Icons.CUBE_16)); - cubeButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeModelType(ModelType.BOX, newValue)); - - sphereButton = new ToggleButton(); - sphereButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_SPHERE + " (S)")); - sphereButton.setGraphic(new ImageView(Icons.SPHERE_16)); - sphereButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeModelType(ModelType.SPHERE, newValue)); - - planeButton = new ToggleButton(); - planeButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_PLANE + " (P)")); - planeButton.setGraphic(new ImageView(Icons.PLANE_16)); - planeButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeModelType(ModelType.QUAD, newValue)); - - lightButton = new ToggleButton(); - lightButton.setTooltip(new Tooltip(Messages.MATERIAL_FILE_EDITOR_ACTION_LIGHT + " (L)")); - lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); - lightButton.setSelected(DEFAULT_LIGHT_ENABLED); - lightButton.selectedProperty().addListener((observable, oldValue, newValue) -> changeLight(newValue)); - - FXUtils.addToPane(createSaveAction(), container); - FXUtils.addToPane(cubeButton, container); - FXUtils.addToPane(sphereButton, container); - FXUtils.addToPane(planeButton, container); - FXUtils.addToPane(lightButton, container); - - DynamicIconSupport.addSupport(cubeButton, sphereButton, planeButton, lightButton); - FXUtils.addClassTo(cubeButton, sphereButton, planeButton, lightButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); - } - - /** - * Handle changing the bucket type. - */ - @FxThread - private void changeBucketType(@NotNull final RenderQueue.Bucket newValue) { - - final T editor3DState = getEditor3DPart(); - editor3DState.changeBucketType(newValue); - - final EditorMaterialEditorState editorState = getEditorState(); - if (editorState != null) editorState.setBucketType(newValue); - } - - /** - * Handle changing the light enabling. - */ - @FxThread - private void changeLight(@NotNull final Boolean newValue) { - - final T editor3DState = getEditor3DPart(); - editor3DState.updateLightEnabled(newValue); - - final EditorMaterialEditorState editorState = getEditorState(); - if (editorState != null) editorState.setLightEnable(newValue); - } - - /** - * @return the button to use a cube. - */ - @FromAnyThread - private @NotNull ToggleButton getCubeButton() { - return notNull(cubeButton); - } - - /** - * @return the button to use a plane. - */ - @FromAnyThread - private @NotNull ToggleButton getPlaneButton() { - return notNull(planeButton); - } - - /** - * @return the button to use a sphere. - */ - @FromAnyThread - private @NotNull ToggleButton getSphereButton() { - return notNull(sphereButton); - } - - /** - * @return the button to use a light. - */ - @FromAnyThread - private @NotNull ToggleButton getLightButton() { - return notNull(lightButton); - } - - /** - * @return the list of RenderQueue.Bucket. - */ - @FromAnyThread - private @NotNull ComboBox getBucketComboBox() { - return notNull(bucketComboBox); - } - - /** - * Handle the changed model type. - */ - @FxThread - private void changeModelType(@NotNull final ModelType modelType, @NotNull final Boolean newValue) { - if (newValue == Boolean.FALSE) return; - - final T editor3DState = getEditor3DPart(); - - final ToggleButton cubeButton = getCubeButton(); - final ToggleButton sphereButton = getSphereButton(); - final ToggleButton planeButton = getPlaneButton(); - - if (modelType == ModelType.BOX) { - cubeButton.setMouseTransparent(true); - sphereButton.setMouseTransparent(false); - planeButton.setMouseTransparent(false); - cubeButton.setSelected(true); - sphereButton.setSelected(false); - planeButton.setSelected(false); - editor3DState.changeMode(modelType); - } else if (modelType == ModelType.SPHERE) { - cubeButton.setMouseTransparent(false); - sphereButton.setMouseTransparent(true); - planeButton.setMouseTransparent(false); - cubeButton.setSelected(false); - sphereButton.setSelected(true); - planeButton.setSelected(false); - editor3DState.changeMode(modelType); - } else if (modelType == ModelType.QUAD) { - cubeButton.setMouseTransparent(false); - sphereButton.setMouseTransparent(false); - planeButton.setMouseTransparent(true); - sphereButton.setSelected(false); - cubeButton.setSelected(false); - planeButton.setSelected(true); - editor3DState.changeMode(modelType); - } - - final EditorMaterialEditorState editorState = getEditorState(); - if (editorState != null) editorState.setModelType(modelType); - } - - @Override - @FxThread - public void notifyFxChangeProperty(@NotNull final Object object, @NotNull final String propertyName) { - if (object instanceof Material) { - getPropertyEditor().refresh(); - } else { - getPropertyEditor().syncFor(object); - } - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/part3d/Advanced3DEditorPart.java b/src/main/java/com/ss/editor/plugin/api/editor/part3d/Advanced3DEditorPart.java deleted file mode 100644 index 1a7f7b71..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/part3d/Advanced3DEditorPart.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.ss.editor.plugin.api.editor.part3d; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Vector3f; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.plugin.api.editor.Advanced3DFileEditor; -import com.ss.editor.part3d.editor.impl.AdvancedAbstractEditor3DPart; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The advanced implementation of 3D part of an editor. - * - * @author JavaSaBr - */ -public abstract class Advanced3DEditorPart extends AdvancedAbstractEditor3DPart { - - /** - * The node on which the camera is looking. - */ - @Nullable - private Node cameraNode; - - public Advanced3DEditorPart(@NotNull final T fileEditor) { - super(fileEditor); - - final Node stateNode = getStateNode(); - stateNode.attachChild(getCameraNode()); - } - - @Override - @FromAnyThread - protected @NotNull Node getNodeForCamera() { - if (cameraNode == null) cameraNode = new Node("CameraNode"); - return cameraNode; - } - - /** - * @return the node on which the camera is looking. - */ - @FromAnyThread - protected @NotNull Node getCameraNode() { - return notNull(cameraNode); - } - - @Override - @JmeThread - protected void undo() { - super.undo(); - getFileEditor().undo(); - } - - @Override - @JmeThread - protected void redo() { - super.redo(); - getFileEditor().redo(); - } - - @Override - @JmeThread - protected void notifyChangedCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, - final float cameraSpeed) { - super.notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed); - EXECUTOR_MANAGER.addFxTask(() -> getFileEditor().notifyChangedCameraSettings(cameraLocation, hRotation, vRotation, targetDistance, cameraSpeed)); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbr3DEditorPart.java b/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbr3DEditorPart.java deleted file mode 100644 index 22678539..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbr3DEditorPart.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.ss.editor.plugin.api.editor.part3d; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.environment.generation.JobProgressAdapter; -import com.jme3.light.LightProbe; -import com.jme3.scene.Node; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.plugin.api.editor.Advanced3DFileEditor; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; - -/** - * The advanced implementation of 3D part of an editor with PBR Light probe. - * - * @author JavaSaBr - */ -public abstract class AdvancedPbr3DEditorPart extends Advanced3DEditorPart { - - @NotNull - private final JobProgressAdapter probeHandler = new JobProgressAdapter() { - - @Override - public void done(final LightProbe result) { - if (!isInitialized()) return; - attachModelNode(); - } - }; - - /** - * The model node. - */ - @NotNull - private final Node modelNode; - - /** - * The count of frames. - */ - private int frame; - - public AdvancedPbr3DEditorPart(@NotNull final T fileEditor) { - super(fileEditor); - this.modelNode = new Node("ModelNode"); - } - - @Override - @JmeThread - public void initialize(@NotNull final AppStateManager stateManager, @NotNull final Application application) { - super.initialize(stateManager, application); - frame = 0; - } - - @Override - @JmeThread - public void cleanup() { - super.cleanup(); - - final Node modelNode = getModelNode(); - modelNode.detachAllChildren(); - - final Node stateNode = getStateNode(); - stateNode.detachChild(modelNode); - } - - /** - * Attach model node to state node. - */ - @JmeThread - private void attachModelNode() { - final Node stateNode = getStateNode(); - stateNode.attachChild(modelNode); - } - - /** - * @return the model node. - */ - @JmeThread - protected @NotNull Node getModelNode() { - return modelNode; - } - - @Override - @JmeThread - public void update(final float tpf) { - super.update(tpf); - - if (frame == 2) { - EditorUtil.updateGlobalLightProbe(probeHandler); - } - - frame++; - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3DEditorPart.java b/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3DEditorPart.java deleted file mode 100644 index c0660b60..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/part3d/AdvancedPbrWithStudioSky3DEditorPart.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ss.editor.plugin.api.editor.part3d; - -import com.jme3.asset.AssetManager; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.jme3.util.SkyFactory; -import com.ss.editor.plugin.api.editor.Advanced3DFileEditor; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; - -/** - * The advanced implementation of 3D part of an editor with PBR Light probe and Studio Sky. - * - * @author JavaSaBr - */ -public class AdvancedPbrWithStudioSky3DEditorPart extends AdvancedPbr3DEditorPart { - - public AdvancedPbrWithStudioSky3DEditorPart(@NotNull final T fileEditor) { - super(fileEditor); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Geometry sky = (Geometry) SkyFactory.createSky(assetManager, "graphics/textures/sky/studio.hdr", - SkyFactory.EnvMapType.EquirectMap); - - final Node stateNode = getStateNode(); - stateNode.attachChild(sky); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/editor/part3d/Base3DEditorPart.java b/src/main/java/com/ss/editor/plugin/api/editor/part3d/Base3DEditorPart.java deleted file mode 100644 index 736c917c..00000000 --- a/src/main/java/com/ss/editor/plugin/api/editor/part3d/Base3DEditorPart.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ss.editor.plugin.api.editor.part3d; - -import com.ss.editor.part3d.editor.impl.AbstractEditor3DPart; -import com.ss.editor.ui.component.editor.FileEditor; -import org.jetbrains.annotations.NotNull; - -/** - * The base implementation of 3D part of an editor. - * - * @author JavaSaBr - */ -public class Base3DEditorPart extends AbstractEditor3DPart { - - public Base3DEditorPart(@NotNull final T fileEditor) { - super(fileEditor); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/file/creator/GenericFileCreator.java b/src/main/java/com/ss/editor/plugin/api/file/creator/GenericFileCreator.java deleted file mode 100644 index 2d265abc..00000000 --- a/src/main/java/com/ss/editor/plugin/api/file/creator/GenericFileCreator.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.ss.editor.plugin.api.file.creator; - -import static com.ss.editor.plugin.api.property.control.PropertyEditorControlFactory.build; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.plugin.api.property.control.PropertyEditorControl; -import com.ss.editor.ui.component.creator.impl.AbstractFileCreator; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.layout.GridPane; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.nio.file.Path; - -/** - * The generic implementation of file creator dialog. - * - * @author JavaSaBr - */ -public class GenericFileCreator extends AbstractFileCreator { - - @NotNull - private static final Array EMPTY_ARRAY = ArrayFactory.asArray(); - - /** - * The settings container. - */ - @Nullable - private GridPane settingsContainer; - - /** - * The result vars of the creator. - */ - @Nullable - private VarTable vars; - - public GenericFileCreator() { - } - - @Override - protected void createSettings(@NotNull GridPane root) { - super.createSettings(root); - - this.settingsContainer = root; - this.vars = VarTable.newInstance(); - - var rowIndex = 1; - - for (var definition : getPropertyDefinitions()) { - var control = build(vars, definition, this::validateFileName); - control.prefWidthProperty().bind(widthProperty()); - root.add(control, 0, rowIndex++, 2, 1); - } - } - - @Override - @FxThread - public void show(@NotNull Window owner) { - super.show(owner); - validateFileName(); - } - - /** - * @return the result vars of the creator. - */ - @FxThread - protected @NotNull VarTable getVars() { - return notNull(vars); - } - - /** - * Get the settings container. - * - * @return the settings container. - */ - @FxThread - private @NotNull GridPane getSettingsContainer() { - return notNull(settingsContainer); - } - - @Override - @FxThread - protected void validateFileName() { - super.validateFileName(); - - var settingsContainer = getSettingsContainer(); - settingsContainer.getChildren().stream() - .filter(PropertyEditorControl.class::isInstance) - .map(PropertyEditorControl.class::cast) - .forEach(PropertyEditorControl::checkDependency); - - var okButton = getOkButton(); - if (okButton == null) { - return; - } - - var result = validate(getVars()); - - if (!okButton.isDisabled()) { - okButton.setDisable(!result); - } - } - - /** - * Validate variables. - * - * @param vars the variables. - * @return true if the all variables are valid. - */ - @FxThread - protected boolean validate(@NotNull VarTable vars) { - return true; - } - - @Override - @BackgroundThread - protected void writeData(@NotNull Path resultFile) throws IOException { - writeData(getVars(), resultFile); - } - - /** - * Write created data to the created file. - * - * @param vars the available variables. - * @param resultFile the result file. - * @throws IOException if was some problem with writing to the result file. - */ - @BackgroundThread - protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { - } - - /** - * Get the list of property definitions. - * - * @return the list of property definitions. - */ - @FromAnyThread - protected @NotNull Array getPropertyDefinitions() { - return EMPTY_ARRAY; - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java deleted file mode 100644 index 6988a677..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The control to edit resource values from asset. - * - * @author JavaSaBr - */ -public abstract class AssetResourcePropertyEditorControl extends ResourcePropertyEditorControl { - - private static final Predicate> DEFAULT_ACTION_TESTER = type -> false; - - private static final Array DEFAULT_EXTENSIONS = ArrayFactory.newArray(String.class); - - protected AssetResourcePropertyEditorControl( - @NotNull final VarTable vars, - @NotNull final PropertyDefinition definition, - @NotNull final Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - /** - * Get the action tester for asset dialog. - * - * @return the action tester. - */ - @FromAnyThread - protected @NotNull Predicate> getActionTester() { - return DEFAULT_ACTION_TESTER; - } - - /** - * Gets a list with available extensions. - * - * @return the list with available extensions. - */ - @FromAnyThread - protected @NotNull Array getExtensions() { - return DEFAULT_EXTENSIONS; - } - - @Override - @FxThread - protected void chooseNew() { - super.chooseNew(); - UiUtils.openFileAssetDialog(this::chooseNew, getExtensions(), getActionTester()); - } - - /** - * Choose the new resource by the file. - * - * @param file the selected file. - */ - @FxThread - protected void chooseNew(@NotNull Path file) { - change(); - reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java deleted file mode 100644 index 4d643297..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.AwtFontSuggestionProvider; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import impl.org.controlsfx.autocompletion.AutoCompletionTextFieldBinding; -import javafx.scene.control.ComboBox; -import javafx.util.StringConverter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.util.Arrays; - -/** - * The control to choose string value from list. - * - * @author JavaSaBr - */ -public class AwtFontPropertyEditorControl extends PropertyEditorControl { - - private static final GraphicsEnvironment GRAPHICS_ENVIRONMENT = GraphicsEnvironment.getLocalGraphicsEnvironment(); - private static final Font[] FONTS = GRAPHICS_ENVIRONMENT.getAllFonts(); - - private static final StringConverter STRING_CONVERTER = new StringConverter<>() { - - @Override - public @NotNull String toString(@Nullable Font font) { - return font == null ? StringUtils.EMPTY : font.getFontName(); - } - - @Override - public @Nullable Font fromString(@NotNull String fontName) { - return Arrays.stream(FONTS) - .filter(font -> font.getFontName().equals(fontName)) - .findAny().orElse(null); - } - }; - - /** - * The list of available options of the string value. - */ - @Nullable - private ComboBox comboBox; - - protected AwtFontPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - comboBox = new ComboBox<>(); - comboBox.getItems().addAll(FONTS); - comboBox.setVisibleRowCount(20); - comboBox.setConverter(STRING_CONVERTER); - comboBox.setEditable(true); - comboBox.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - var selectionModel = comboBox.getSelectionModel(); - - var editor = comboBox.getEditor(); - var binding = new AutoCompletionTextFieldBinding(editor, - new AwtFontSuggestionProvider(comboBox.getItems()), STRING_CONVERTER); - binding.setOnAutoCompleted(event -> selectionModel.select(event.getCompletion())); - binding.prefWidthProperty().bind(comboBox.widthProperty().multiply(1.3)); - - FxControlUtils.onSelectedItemChange(comboBox, newValue -> { - var executorManager = ExecutorManager.getInstance(); - executorManager.addFxTask(() -> editor.positionCaret(newValue.getFontName().length())); - }); - - FxControlUtils.onSelectedItemChange(comboBox, this::change); - - FxUtils.addClass(editor, - CssClasses.TRANSPARENT_TEXT_FIELD, CssClasses.TEXT_FIELD_IN_COMBO_BOX) - .addClass(comboBox, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(this, comboBox); - } - - /** - * @return The list of available options of the string value. - */ - @FxThread - private @NotNull ComboBox getComboBox() { - return notNull(comboBox); - } - - @Override - @FxThread - public void reload() { - super.reload(); - var value = getPropertyValue(); - getComboBox().getSelectionModel() - .select(value); - } - - @Override - @FxThread - protected void changeImpl() { - - var selectionItem = getComboBox() - .getSelectionModel() - .getSelectedItem(); - - setPropertyValue(selectionItem); - - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java deleted file mode 100644 index 52766ca3..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.CheckBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The control to edit boolean values. - * - * @author JavaSaBr - */ -public class BooleanPropertyEditorControl extends PropertyEditorControl { - - /** - * The {@link CheckBox} with current value. - */ - @Nullable - private CheckBox checkBox; - - protected BooleanPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - checkBox = new CheckBox(); - checkBox.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - FxControlUtils.onSelectedChange(checkBox, this::change); - - FxUtils.addClass(checkBox, CssClasses.PROPERTY_CONTROL_CHECK_BOX); - FxUtils.addChild(this, checkBox); - } - - /** - * Get the check box with current value. - * - * @return the check box with current value. - */ - @FxThread - private @NotNull CheckBox getCheckBox() { - return notNull(checkBox); - } - - @Override - @FxThread - public void reload() { - super.reload(); - getCheckBox().setSelected(Boolean.TRUE.equals(getPropertyValue())); - } - - @Override - @FxThread - protected void changeImpl() { - setPropertyValue(getCheckBox().isSelected()); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java deleted file mode 100644 index b95ac5a4..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import org.jetbrains.annotations.NotNull; - -/** - * The control to edit resource values from classpath. - * - * @author JavaSaBr - */ -public class ClasspathResourcePropertyControl extends ResourcePropertyEditorControl { - - /** - * The target extension. - */ - @NotNull - private final String extension; - - public ClasspathResourcePropertyControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - this.extension = notNull(definition.getExtension()); - } - - @Override - @FxThread - protected void chooseNew() { - super.chooseNew(); - - var resourceManager = ResourceManager.getInstance(); - var resources = resourceManager.getAvailableResources(extension); - - UiUtils.openResourceAssetDialog(this::chooseNew, this::validate, resources); - } - - /** - * Choose the new resource by the path - * - * @param resource the selected resource. - */ - @FxThread - private void chooseNew(@NotNull String resource) { - setPropertyValue(resource); - change(); - reload(); - } - - /** - * Validate the selected resource. - * - * @param resource the selected resource. - * @return the message of problems or null if all are ok. - */ - @FxThread - private String validate(@NotNull final String resource) { - - var extension = FileUtils.getExtension(resource); - if (StringUtils.isEmpty(extension)) { - return Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE; - } - - return null; - } - - @Override - @FxThread - public void reload() { - - var resource = getPropertyValue(); - var resourceLabel = getResourceLabel(); - resourceLabel.setText(resource == null ? NOT_SELECTED : resource); - - super.reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java deleted file mode 100644 index eb35d7d5..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.ColorRGBA; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ColorPicker; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The control to edit color values. - * - * @author JavaSaBr - */ -public class ColorPropertyEditorControl extends PropertyEditorControl { - - /** - * The color picker. - */ - @Nullable - private ColorPicker colorPicker; - - protected ColorPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - colorPicker = new ColorPicker(); - colorPicker.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - FxControlUtils.onColorChange(colorPicker, this::change); - - FxUtils.addClass(colorPicker, CssClasses.PROPERTY_CONTROL_COLOR_PICKER); - FxUtils.addChild(this, colorPicker); - } - - /** - * Get the color picker. - * - * @return the color picker. - */ - @FxThread - private @NotNull ColorPicker getColorPicker() { - return notNull(colorPicker); - } - - @Override - @FxThread - public void reload() { - super.reload(); - getColorPicker().setValue(UiUtils.from(getPropertyValue())); - } - - @Override - @FxThread - protected void changeImpl() { - var colorPicker = getColorPicker(); - setPropertyValue(UiUtils.from(colorPicker.getValue())); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ComboBoxPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ComboBoxPropertyEditorControl.java deleted file mode 100644 index d061e6fe..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ComboBoxPropertyEditorControl.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ComboBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The combo box based property control. - * - * @author JavaSaBr - */ -public class ComboBoxPropertyEditorControl extends PropertyEditorControl { - - /** - * The list of available options. - */ - @Nullable - private ComboBox comboBox; - - protected ComboBoxPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - comboBox = new ComboBox<>(); - comboBox.setVisibleRowCount(20); - comboBox.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - FxControlUtils.onSelectedItemChange(comboBox, this::change); - - FxUtils.addClass(comboBox, CssClasses.PROPERTY_CONTROL_COMBO_BOX); - FxUtils.addChild(this, comboBox); - } - - /** - * Get the list of available options. - * - * @return the list of available options. - */ - @FxThread - protected @NotNull ComboBox getComboBox() { - return notNull(comboBox); - } - - @Override - @FxThread - public void reload() { - super.reload(); - getComboBox().getSelectionModel() - .select(getPropertyValue()); - } - - @Override - @FxThread - protected void changeImpl() { - var comboBox = getComboBox(); - var selectionModel = comboBox.getSelectionModel(); - setPropertyValue(selectionModel.getSelectedItem()); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java deleted file mode 100644 index 7c2ceb8d..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.ClassUtils; -import com.ss.rlib.common.util.VarTable; -import org.jetbrains.annotations.NotNull; - -/** - * The property control to edit enum values. - * - * @author JavaSaBr - */ -public class EnumPropertyEditorControl> extends ComboBoxPropertyEditorControl { - - protected EnumPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - - var defaultValue = ClassUtils.unsafeCast(notNull(definition.getDefaultValue())); - var enumConstants = EditorUtil.getEnumValues(defaultValue.getClass()); - - getComboBox().getItems() - .addAll(enumConstants); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java deleted file mode 100644 index 339f6e81..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.dialog.file.chooser.ExternalFileEditorDialog; -import com.ss.rlib.common.util.VarTable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The control to edit files from file system. - * - * @author JavaSaBr - */ -public class ExternalFileResourcePropertyControl extends ResourcePropertyEditorControl { - - /** - * The target extension. - */ - @Nullable - private final String extension; - - public ExternalFileResourcePropertyControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - this.extension = definition.getExtension(); - } - - @Override - @FxThread - protected void chooseNew() { - super.chooseNew(); - - var dialog = new ExternalFileEditorDialog(this::openExternalFile); - dialog.setTitleText(Messages.ASSET_EDITOR_DIALOG_TITLE); - dialog.setInitDirectory(Paths.get(System.getProperty("user.home"))); - dialog.show(); - } - - /** - * Handle selected file. - * - * @param path the selected file. - */ - @FxThread - private void openExternalFile(@NotNull Path path) { - setPropertyValue(path); - change(); - reload(); - } - - - @Override - @FxThread - public void reload() { - - var resource = getPropertyValue(); - var resourceLabel = getResourceLabel(); - resourceLabel.setText(resource == null ? NOT_SELECTED : resource.toString()); - - super.reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java deleted file mode 100644 index 742ce025..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The control to edit file values from asset folder. - * - * @author JavaSaBr - */ -public class FileAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { - - @NotNull - private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class; - - /** - * The list of target extensions. - */ - @NotNull - private final Array extensions; - - public FileAssetResourcePropertyControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - this.extensions = ArrayFactory.asArray(notNull(definition.getExtension())); - } - - @Override - @FromAnyThread - public @NotNull Predicate> getActionTester() { - return ACTION_TESTER; - } - - @Override - @FromAnyThread - protected @NotNull Array getExtensions() { - return extensions; - } - - @Override - @FxThread - protected void chooseNew(@NotNull Path file) { - setPropertyValue(notNull(getAssetFile(file))); - super.chooseNew(file); - } - - @Override - @FxThread - public void reload() { - - var file = getPropertyValue(); - - var resourceLabel = getResourceLabel(); - resourceLabel.setText(file == null ? NOT_SELECTED : toAssetPath(file)); - - super.reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java deleted file mode 100644 index 8b0c90c6..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.control.input.FloatTextField; -import org.jetbrains.annotations.NotNull; - -/** - * The control to edit float values. - * - * @author JavaSaBr - */ -public class FloatPropertyEditorControl extends TypedTextFieldPropertyEditorControl { - - public FloatPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected @NotNull FloatTextField createField() { - return new FloatTextField(); - } - - /** - * Set min/max values. - * - * @param min the min value. - * @param max the max value. - */ - @FxThread - public void setMinMax(float min, float max) { - if (Float.isNaN(min) || Float.isNaN(max)) return; - getValueField().setMinMax(min, max); - } - - @Override - @FxThread - public void reload() { - super.reload(); - var value = getPropertyValue(); - getValueField().setValue(value == null ? 0 : value); - } - - @Override - @FxThread - protected void changeImpl() { - setPropertyValue(getValueField().getValue()); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java deleted file mode 100644 index e7a79b99..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The control to edit folder values from asset folder. - * - * @author JavaSaBr - */ -public class FolderAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { - - @NotNull - private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class; - - public FolderAssetResourcePropertyControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FromAnyThread - public @NotNull Predicate> getActionTester() { - return ACTION_TESTER; - } - - @Override - @FxThread - protected void chooseNew() { - UiUtils.openFolderAssetDialog(this::chooseNew, getActionTester()); - } - - @Override - @FxThread - protected void chooseNew(@NotNull Path file) { - setPropertyValue(notNull(getAssetFile(file))); - super.chooseNew(file); - } - - @Override - @FxThread - public void reload() { - - var file = getPropertyValue(); - var assetPath = file == null ? NOT_SELECTED : toAssetPath(file); - - var resourceLabel = getResourceLabel(); - resourceLabel.setText(StringUtils.isEmpty(assetPath) ? "/" : assetPath); - - super.reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java deleted file mode 100644 index 4e4d2f61..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.ifNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.control.input.IntegerTextField; -import org.jetbrains.annotations.NotNull; - -/** - * The property control to edit integer values. - * - * @author JavaSaBr - */ -public class IntegerPropertyEditorControl extends TypedTextFieldPropertyEditorControl { - - public IntegerPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected @NotNull IntegerTextField createField() { - return new IntegerTextField(); - } - - /** - * Set min/max values. - * - * @param min the min value. - * @param max the max value. - */ - @FxThread - public void setMinMax(float min, float max) { - if (Float.isNaN(min) || Float.isNaN(max)) return; - getValueField().setMinMax((int) min, (int) max); - } - - @Override - @FxThread - public void reload() { - super.reload(); - getValueField().setValue(ifNull(getPropertyValue(), 0)); - } - - @Override - @FxThread - protected void changeImpl() { - setPropertyValue(getValueField().getValue()); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java deleted file mode 100644 index d07f2c66..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.common.util.ClassUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.input.DataFormat; -import javafx.scene.input.DragEvent; -import javafx.scene.input.TransferMode; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.List; - -/** - * The control to edit resource values. - * - * @author JavaSaBr - */ -public abstract class ResourcePropertyEditorControl extends PropertyEditorControl { - - protected static final String NOT_SELECTED = - Messages.RESOURCE_PROPERTY_EDIT_CONTROL_NOTHING_IS_SELECTED; - - /** - * The label with name of the resource. - */ - @Nullable - private Label resourceLabel; - - protected ResourcePropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - setOnDragOver(this::dragOver); - setOnDragDropped(this::dragDropped); - setOnDragExited(this::dragExited); - FxUtils.addClass(this, CssClasses.PROPERTY_CONTROL_RESOURCE); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - resourceLabel = new Label(NOT_SELECTED); - - var changeButton = new Button(); - changeButton.setGraphic(new ImageView(Icons.ADD_16)); - changeButton.setOnAction(event -> chooseNew()); - - var removeButton = new Button(); - removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); - removeButton.setOnAction(event -> removeCurrent()); - removeButton.disableProperty() - .bind(resourceLabel.textProperty().isEqualTo(NOT_SELECTED)); - - var container = new HBox(resourceLabel, changeButton, removeButton); - container.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - resourceLabel.prefWidthProperty() - .bind(container.widthProperty()); - - FxUtils.addChild(this, container); - - FxUtils.addClass(container, - CssClasses.DEF_HBOX, CssClasses.TEXT_INPUT_CONTAINER) - .addClass(changeButton, removeButton, - CssClasses.FLAT_BUTTON, CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON) - .addClass(resourceLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL); - - DynamicIconSupport.addSupport(changeButton); - } - - /** - * Choose a new resource. - */ - @FxThread - protected void chooseNew() { - - } - - /** - * Remove the current resource. - */ - @FxThread - protected void removeCurrent() { - setPropertyValue(null); - change(); - reload(); - } - - /** - * Handle grad exiting. - */ - @FxThread - private void dragExited(@NotNull DragEvent dragEvent) { - } - - /** - * Handle dropped files to editor. - */ - @FxThread - private void dragDropped(@NotNull DragEvent dragEvent) { - - var dragboard = dragEvent.getDragboard(); - var files = ClassUtils.>unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - var file = files.get(0); - if (!canAccept(file)) { - return; - } - - handleFile(file); - } - - /** - * Handle a dropped file. - * - * @param file the dropped file. - */ - @FxThread - protected void handleFile(@NotNull File file) { - } - - /** - * Handle drag over. - */ - @FxThread - private void dragOver(@NotNull DragEvent dragEvent) { - - var dragboard = dragEvent.getDragboard(); - var files = ClassUtils.>unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - var file = files.get(0); - if (!canAccept(file)) { - return; - } - - var transferModes = dragboard.getTransferModes(); - var isCopy = transferModes.contains(TransferMode.COPY); - - dragEvent.acceptTransferModes(isCopy ? TransferMode.COPY : TransferMode.MOVE); - dragEvent.consume(); - } - - @FxThread - protected boolean canAccept(@NotNull File file) { - return false; - } - - /** - * @return the label with name of the resource. - */ - @FxThread - protected @NotNull Label getResourceLabel() { - return notNull(resourceLabel); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java deleted file mode 100644 index 1447d333..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.nio.file.Path; - -/** - * The control to edit spatial values from asset. - * - * @author JavaSaBr - */ -public class SpatialAssetResourcePropertyControl extends AssetResourcePropertyEditorControl { - - @NotNull - private static final Array EXTENSIONS = ArrayFactory.newArray(String.class); - - static { - EXTENSIONS.add(FileExtensions.JME_OBJECT); - } - - public SpatialAssetResourcePropertyControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FromAnyThread - protected @NotNull Array getExtensions() { - return EXTENSIONS; - } - - @Override - @FxThread - protected void chooseNew(@NotNull Path file) { - - var assetManager = EditorUtil.getAssetManager(); - - var assetFile = notNull(getAssetFile(file)); - var modelKey = new ModelKey(toAssetPath(assetFile)); - var spatial = findResource(assetManager, modelKey); - - setPropertyValue(unsafeCast(spatial)); - - super.chooseNew(file); - } - - /** - * Find a resource rom asset folder by the model key. - * - * @param assetManager the asset manager. - * @param modelKey the model key. - * @return the target resource. - */ - @FxThread - protected @Nullable T findResource(@NotNull AssetManager assetManager, @NotNull ModelKey modelKey) { - return unsafeCast(assetManager.loadModel(modelKey)); - } - - @Override - @FxThread - protected boolean canAccept(@NotNull File file) { - return EXTENSIONS.contains(FileUtils.getExtension(file.getName())); - } - - @Override - @FxThread - protected void handleFile(@NotNull File file) { - chooseNew(file.toPath()); - } - - @Override - @FxThread - public void reload() { - - var model = getPropertyValue(); - var rootKey = EditorUtil.findRootKey(model); - - var resourceLabel = getResourceLabel(); - resourceLabel.setText(rootKey == null ? NOT_SELECTED : rootKey + "[" + model.getName() + "]"); - - super.reload(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java deleted file mode 100644 index 51b16f8c..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.TextField; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The control to edit string values. - * - * @author JavaSaBr - */ -public class StringPropertyEditorControl extends PropertyEditorControl { - - /** - * The value field. - */ - @Nullable - private TextField valueField; - - protected StringPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - valueField = new TextField(); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - FxControlUtils.onTextChange(valueField, this::change); - - FxUtils.addClass(valueField, CssClasses.PROPERTY_CONTROL_COMBO_BOX); - FxUtils.addChild(this, valueField); - } - - /** - * Get the value field. - * - * @return the value field. - */ - @FxThread - private @NotNull TextField getValueField() { - return notNull(valueField); - } - - @Override - @FxThread - public void reload() { - super.reload(); - var value = getPropertyValue(); - getValueField().setText(value == null ? "" : value); - } - - @Override - @FxThread - protected void changeImpl() { - setPropertyValue(getValueField().getText()); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java deleted file mode 100644 index 64fe6b3a..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/TypedTextFieldPropertyEditorControl.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.control.input.TypedTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The typed text field base property control. - * - * @author JavaSaBr - */ -public abstract class TypedTextFieldPropertyEditorControl> - extends PropertyEditorControl { - - /** - * The value field. - */ - @Nullable - private F valueField; - - protected TypedTextFieldPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - valueField = createField(); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - FxControlUtils.onTextChange(valueField, this::change); - - FxUtils.addClass(valueField, CssClasses.PROPERTY_CONTROL_COMBO_BOX); - FxUtils.addChild(this, valueField); - } - - /** - * Create a new field. - * - * @return the new field. - */ - @FxThread - protected abstract @NotNull F createField(); - - /** - * Get the value field. - * - * @return the value field. - */ - @FxThread - protected @NotNull F getValueField() { - return notNull(valueField); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java deleted file mode 100644 index 3145a6e2..00000000 --- a/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.ss.editor.plugin.api.property.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.layout.GridPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The control to edit float values. - * - * @author JavaSaBr - */ -public class Vector3fPropertyEditorControl extends PropertyEditorControl { - - /** - * The field X. - */ - @Nullable - private FloatTextField xField; - - /** - * The field Y. - */ - @Nullable - private FloatTextField yField; - - /** - * The field Z. - */ - @Nullable - private FloatTextField zField; - - protected Vector3fPropertyEditorControl( - @NotNull VarTable vars, - @NotNull PropertyDefinition definition, - @NotNull Runnable validationCallback - ) { - super(vars, definition, validationCallback); - } - - @Override - @FxThread - protected void createComponents() { - super.createComponents(); - - var resultWidth = widthProperty() - .multiply(DEFAULT_FIELD_W_PERCENT); - - var gridPane = new GridPane(); - gridPane.prefWidthProperty() - .bind(resultWidth); - - var fieldWidth = gridPane.widthProperty() - .divide(3); - - xField = new FloatTextField(); - xField.prefWidthProperty().bind(fieldWidth); - - yField = new FloatTextField(); - yField.prefWidthProperty().bind(fieldWidth); - - zField = new FloatTextField(); - zField.prefWidthProperty().bind(fieldWidth); - - gridPane.add(xField, 0, 0); - gridPane.add(yField, 1, 0); - gridPane.add(zField, 2, 0); - - FxControlUtils.onValueChange(xField, this::change); - FxControlUtils.onValueChange(yField, this::change); - FxControlUtils.onValueChange(zField, this::change); - - FxUtils.addClass(gridPane, - CssClasses.DEF_GRID_PANE, CssClasses.TEXT_INPUT_CONTAINER) - .addClass(xField, yField, zField, - CssClasses.TRANSPARENT_TEXT_FIELD, - CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD); - - FxUtils.addChild(this, gridPane); - - UiUtils.addFocusBinding(gridPane, xField, yField, zField); - } - - /** - * Get the field X. - * - * @return the field X. - */ - @FxThread - private @NotNull FloatTextField getXField() { - return notNull(xField); - } - - /** - * Get the field Y. - * - * @return the field Y. - */ - @FxThread - private @NotNull FloatTextField getYField() { - return notNull(yField); - } - - /** - * Get the field Z. - * - * @return the field Z. - */ - @FxThread - private @NotNull FloatTextField getZField() { - return notNull(zField); - } - - @Override - @FxThread - public void reload() { - super.reload(); - - var value = getPropertyValue(); - - var xField = getXField(); - xField.setValue(value == null ? 0 : value.getX()); - - var yField = getYField(); - yField.setValue(value == null ? 0 : value.getY()); - - var zField = getZField(); - zField.setValue(value == null ? 0 : value.getZ()); - } - - @Override - @FxThread - protected void changeImpl() { - var xField = getXField(); - var yField = getYField(); - var zField = getZField(); - setPropertyValue(new Vector3f(xField.getValue(), yField.getValue(), zField.getValue())); - super.changeImpl(); - } -} diff --git a/src/main/java/com/ss/editor/plugin/api/settings/SettingsProviderRegistry.java b/src/main/java/com/ss/editor/plugin/api/settings/SettingsProviderRegistry.java deleted file mode 100644 index a6c0cba6..00000000 --- a/src/main/java/com/ss/editor/plugin/api/settings/SettingsProviderRegistry.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.ss.editor.plugin.api.settings; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.DefaultSettingsProvider; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -/** - * The registry of all settings providers. - * - * @author JavaSaBr - */ -public class SettingsProviderRegistry { - - private static final SettingsProviderRegistry INSTANCE = new SettingsProviderRegistry(); - - @FromAnyThread - public static @NotNull SettingsProviderRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of settings providers. - */ - @NotNull - private final Array providers; - - private SettingsProviderRegistry() { - this.providers = ArrayFactory.newArray(SettingsProvider.class); - register(new DefaultSettingsProvider()); - } - - /** - * Register the new settings provider. - * - * @param settingsProvider the new settings provider. - */ - @FxThread - public void register(@NotNull SettingsProvider settingsProvider) { - this.providers.add(settingsProvider); - } - - /** - * Get all available settings property definitions. - * - * @return all available settings property definitions. - */ - @FxThread - public @NotNull Array getDefinitions() { - - var result = ArrayFactory.newArray(SettingsPropertyDefinition.class); - - providers.forEach(result, - (provider, definitions) -> definitions.addAll(provider.getDefinitions())); - - return result; - } - - /** - * Check the property if this property requires restarting of editor. - * - * @param propertyId the property id. - * @return true if need to restart to apply changes for this property. - */ - @FxThread - public boolean isRequiredRestart(@NotNull String propertyId) { - return providers.search(propertyId, - (provider, id) -> provider.isRequiredRestart(propertyId)) != null; - } - - /** - * Check the property if this property requires updating of classpath. - * - * @param propertyId the property id. - * @return true if need to update classpath to apply changes for this property. - */ - @FxThread - public boolean isRequiredUpdateClasspath(@NotNull String propertyId) { - return providers.search(propertyId, - (provider, id) -> provider.isRequiredRestart(propertyId)) != null; - } - - /** - * Check the property if this property requires reshaping of 3D view. - * - * @param propertyId the property id. - * @return true if need to reshape 3D view to apply changes for this property. - */ - @FxThread - public boolean isRequiredReshape3DView(@NotNull String propertyId) { - return providers.search(propertyId, - (provider, id) -> provider.isRequiredRestart(propertyId)) != null; - } -} diff --git a/src/main/java/com/ss/editor/remote/control/client/LoadLocalClassesClientCommand.java b/src/main/java/com/ss/editor/remote/control/client/LoadLocalClassesClientCommand.java deleted file mode 100644 index f4c90971..00000000 --- a/src/main/java/com/ss/editor/remote/control/client/LoadLocalClassesClientCommand.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.remote.control.client; - -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.manager.ClasspathManager; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.network.ConnectionOwner; -import com.ss.rlib.common.network.annotation.PacketDescription; -import com.ss.rlib.common.util.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.nio.ByteBuffer; -import java.nio.file.Paths; - -/** - * The command to load local libraries in jMB. - * - * @author JavaSaBr - */ -@PacketDescription(id = 3) -public class LoadLocalClassesClientCommand extends ClientCommand { - - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - @Override - @BackgroundThread - protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { - - var outputPath = readString(buffer); - var output = StringUtils.isEmpty(outputPath) ? null : Paths.get(outputPath); - - ClasspathManager.getInstance() - .loadLocalClasses(output); - - EXECUTOR_MANAGER.addJmeTask(() -> EditorUtil.getAssetManager().clearCache()); - } -} diff --git a/src/main/java/com/ss/editor/remote/control/client/LoadLocalLibrariesClientCommand.java b/src/main/java/com/ss/editor/remote/control/client/LoadLocalLibrariesClientCommand.java deleted file mode 100644 index d6d3c7f5..00000000 --- a/src/main/java/com/ss/editor/remote/control/client/LoadLocalLibrariesClientCommand.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ss.editor.remote.control.client; - -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.manager.ClasspathManager; -import com.ss.rlib.common.network.ConnectionOwner; -import com.ss.rlib.common.network.annotation.PacketDescription; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The command to load local libraries in jMB. - * - * @author JavaSaBr - */ -@PacketDescription(id = 2) -public class LoadLocalLibrariesClientCommand extends ClientCommand { - - @Override - @BackgroundThread - protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { - - var libraries = ArrayFactory.newArray(Path.class); - - for (int i = 0, length = readInt(buffer); i < length; i++) { - libraries.add(Paths.get(readString(buffer))); - } - - ClasspathManager.getInstance(). - loadLocalLibraries(libraries); - } -} diff --git a/src/main/java/com/ss/editor/remote/control/client/OpenFileClientCommand.java b/src/main/java/com/ss/editor/remote/control/client/OpenFileClientCommand.java deleted file mode 100644 index 5e28ae3c..00000000 --- a/src/main/java/com/ss/editor/remote/control/client/OpenFileClientCommand.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.remote.control.client; - -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.component.bar.action.OpenAssetAction; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.AssetComponentLoadedEvent; -import com.ss.editor.ui.event.impl.RequestedOpenFileEvent; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.network.ConnectionOwner; -import com.ss.rlib.common.network.annotation.PacketDescription; -import javafx.event.EventHandler; -import org.jetbrains.annotations.NotNull; - -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The command to open a file. - * - * @author JavaSaBr - */ -@PacketDescription(id = 1) -public class OpenFileClientCommand extends ClientCommand { - - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - @Override - @BackgroundThread - protected void readImpl(@NotNull ConnectionOwner owner, @NotNull ByteBuffer buffer) { - - var assetPath = Paths.get(readString(buffer)); - var fileToOpen = Paths.get(readString(buffer)); - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - - if (assetPath.equals(currentAsset)) { - EXECUTOR_MANAGER.addFxTask(() -> openFile(fileToOpen)); - } else { - EXECUTOR_MANAGER.addFxTask(() -> { - - final OpenAssetAction action = new OpenAssetAction(); - action.openAssetFolder(assetPath); - - var eventHandler = new EventHandler() { - - @Override - public void handle(@NotNull AssetComponentLoadedEvent event) { - FX_EVENT_MANAGER.removeEventHandler(AssetComponentLoadedEvent.EVENT_TYPE, this); - openFile(fileToOpen); - } - }; - - FX_EVENT_MANAGER.addEventHandler(AssetComponentLoadedEvent.EVENT_TYPE, eventHandler); - }); - - } - } - - /** - * Open the file. - * - * @param fileToOpen the file. - */ - private void openFile(@NotNull Path fileToOpen) { - FX_EVENT_MANAGER.notify(new RequestedOpenFileEvent(fileToOpen)); - EditorUtil.requestFxFocus(); - } -} diff --git a/src/main/java/com/ss/editor/ui/builder/EditorFxSceneBuilder.java b/src/main/java/com/ss/editor/ui/builder/EditorFxSceneBuilder.java deleted file mode 100644 index c469f2ac..00000000 --- a/src/main/java/com/ss/editor/ui/builder/EditorFxSceneBuilder.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.ss.editor.ui.builder; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_THEME; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_UI_THEME; -import static javafx.scene.paint.Color.TRANSPARENT; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.asset.AssetComponent; -import com.ss.editor.ui.component.bar.EditorMenuBarComponent; -import com.ss.editor.ui.component.editor.area.EditorAreaComponent; -import com.ss.editor.ui.component.log.LogView; -import com.ss.editor.ui.component.split.pane.GlobalBottomToolSplitPane; -import com.ss.editor.ui.component.split.pane.GlobalLeftToolSplitPane; -import com.ss.editor.ui.component.tab.GlobalBottomToolComponent; -import com.ss.editor.ui.component.tab.GlobalLeftToolComponent; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.css.CssRegistry; -import com.ss.editor.ui.event.EventRedirector; -import com.ss.editor.ui.scene.EditorFxScene; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.Group; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; -import org.jetbrains.annotations.NotNull; - -/** - * The scene builder for building a scene for the Editor. - * - * @author JavaSaBr - */ -public class EditorFxSceneBuilder { - - private static final CssRegistry CSS_REGISTRY = CssRegistry.getInstance(); - - /** - * The path to the base CSS styles. - */ - public static final String CSS_FILE_BASE = "ui/css/base.css"; - - /** - * The path to the external CSS styles. - */ - public static final String CSS_FILE_EXTERNAL = "ui/css/external.css"; - - /** - * The path to the custom ids CSS styles. - */ - public static final String CSS_FILE_CUSTOM_IDS = "ui/css/custom_ids.css"; - - /** - * The path to the custom classes CSS styles. - */ - public static final String CSS_FILE_CUSTOM_CLASSES = "ui/css/custom_classes.css"; - - static { - CSS_REGISTRY.register(CSS_FILE_BASE, EditorFxSceneBuilder.class.getClassLoader()); - CSS_REGISTRY.register(CSS_FILE_EXTERNAL, EditorFxSceneBuilder.class.getClassLoader()); - CSS_REGISTRY.register(CSS_FILE_CUSTOM_IDS, EditorFxSceneBuilder.class.getClassLoader()); - CSS_REGISTRY.register(CSS_FILE_CUSTOM_CLASSES, EditorFxSceneBuilder.class.getClassLoader()); - } - - /** - * Build editor fx scene. - * - * @param stage the stage - * @return the editor fx scene - */ - @FxThread - public static @NotNull EditorFxScene build(@NotNull Stage stage) { - - var editorConfig = EditorConfig.getInstance(); - var theme = editorConfig.getEnum(PREF_UI_THEME, PREF_DEFAULT_THEME); - - var root = new Group(); - - var scene = new EditorFxScene(root); - scene.setFill(TRANSPARENT); - scene.setRoot(root); - - var stylesheets = scene.getStylesheets(); - stylesheets.addAll(CSS_REGISTRY.getAvailableCssFiles()); - stylesheets.add(theme.getCssFile()); - - var container = scene.getContainer(); - - build(scene, container, stage); - - stage.setScene(scene); - - return scene; - } - - @FxThread - private static void build(@NotNull EditorFxScene scene, @NotNull StackPane container, @NotNull Stage stage) { - - var canvas = scene.getCanvas(); - var barComponent = new EditorMenuBarComponent(); - var editorAreaComponent = new EditorAreaComponent(); - - new EventRedirector(editorAreaComponent, canvas, stage); - - var leftSplitContainer = new GlobalLeftToolSplitPane(scene); - leftSplitContainer.prefHeightProperty() - .bind(container.heightProperty()); - - var bottomSplitContainer = new GlobalBottomToolSplitPane(scene); - var globalLeftToolComponent = new GlobalLeftToolComponent(leftSplitContainer); - globalLeftToolComponent.addComponent(new AssetComponent(), Messages.EDITOR_TOOL_ASSET); - - var globalBottomToolComponent = new GlobalBottomToolComponent(bottomSplitContainer); - globalBottomToolComponent.addComponent(LogView.getInstance(), Messages.LOG_VIEW_TITLE); - - leftSplitContainer.initFor(globalLeftToolComponent, bottomSplitContainer); - bottomSplitContainer.initFor(globalBottomToolComponent, editorAreaComponent); - - FxUtils.addClass(leftSplitContainer, bottomSplitContainer, - CssClasses.MAIN_SPLIT_PANEL); - - FxUtils.addChild(container, new VBox(barComponent, leftSplitContainer)); - - leftSplitContainer.prefWidthProperty() - .bind(container.widthProperty()); - barComponent.prefWidthProperty() - .bind(container.widthProperty()); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/ScreenComponent.java b/src/main/java/com/ss/editor/ui/component/ScreenComponent.java deleted file mode 100644 index c0a26e49..00000000 --- a/src/main/java/com/ss/editor/ui/component/ScreenComponent.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ss.editor.ui.component; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.Nullable; - -/** - * The interface to implement a scene component. - * - * @author JavaSaBr - */ -public interface ScreenComponent { - - /** - * Gets the component id. - * - * @return the component id. - */ - @FromAnyThread - default @Nullable String getComponentId() { - return null; - } - - /** - * Notify about finishing building the result scene. - */ - @FxThread - default void notifyFinishBuild() { - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/AssetBarComponent.java b/src/main/java/com/ss/editor/ui/component/asset/AssetBarComponent.java deleted file mode 100644 index 44e43f04..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/AssetBarComponent.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.ss.editor.ui.component.asset; - -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.RequestedRefreshAssetEvent; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.control.Button; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; - -/** - * The toolbar of the {@link AssetComponent} with actions. - * - * @author JavaSaBr. - */ -public class AssetBarComponent extends HBox { - - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * Instantiates a new Asset bar component. - */ - public AssetBarComponent() { - - final Button refreshAction = new Button(); - refreshAction.setGraphic(new ImageView(Icons.REFRESH_18)); - refreshAction.setOnAction(event -> FX_EVENT_MANAGER.notify(new RequestedRefreshAssetEvent())); - - FXUtils.addToPane(refreshAction, this); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/AssetTreeContextMenuFillerRegistry.java b/src/main/java/com/ss/editor/ui/component/asset/tree/AssetTreeContextMenuFillerRegistry.java deleted file mode 100644 index 9abb9172..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/AssetTreeContextMenuFillerRegistry.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.ss.editor.ui.component.asset.tree; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.impl.FileAssetTreeSingleContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.impl.ResourceAssetTreeSingleContextMenuFiller; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -/** - * The registry class to collect all available context menu filler. - * - * @author JavaSaBr - */ -public class AssetTreeContextMenuFillerRegistry { - - @NotNull - private static final AssetTreeContextMenuFillerRegistry INSTANCE = new AssetTreeContextMenuFillerRegistry(); - - @NotNull - public static AssetTreeContextMenuFillerRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of single fillers. - */ - @NotNull - private final Array singleFillers; - - /** - * The list of multi fillers. - */ - @NotNull - private final Array multiFillers; - - private AssetTreeContextMenuFillerRegistry() { - this.singleFillers = ArrayFactory.newArray(AssetTreeSingleContextMenuFiller.class); - this.multiFillers = ArrayFactory.newArray(AssetTreeMultiContextMenuFiller.class); - registerSingle(new FileAssetTreeSingleContextMenuFiller()); - registerSingle(new ResourceAssetTreeSingleContextMenuFiller()); - registerMulti(new FileAssetTreeSingleContextMenuFiller()); - registerMulti(new ResourceAssetTreeSingleContextMenuFiller()); - } - - /** - * Register a new single context menu filler. - * - * @param filler the single context menu filler. - */ - @FromAnyThread - public void registerSingle(@NotNull final AssetTreeSingleContextMenuFiller filler) { - this.singleFillers.add(filler); - } - - /** - * Register a new multiply context menu filler. - * - * @param filler the multiply context menu filler. - */ - @FromAnyThread - public void registerMulti(@NotNull final AssetTreeMultiContextMenuFiller filler) { - this.multiFillers.add(filler); - } - - /** - * Gets the list of available single context menu singleFillers. - * - * @return the list of single context menu filler. - */ - @FromAnyThread - public @NotNull Array getSingleFillers() { - return singleFillers; - } - - /** - * Gets the list of available multiply context menu singleFillers. - * - * @return the list of multiply context menu filler. - */ - @FromAnyThread - public @NotNull Array getMultiFillers() { - return multiFillers; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileAction.java deleted file mode 100644 index 4bdc6a35..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileAction.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.file.converter.FileConverterDescription; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import com.ss.rlib.common.util.array.Array; - -/** - * The action to transformation a file. - * - * @author JavaSaBr - */ -public class ConvertFileAction extends Menu { - - public ConvertFileAction(@NotNull final ResourceElement element, - @NotNull final Array descriptions) { - - setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_CONVERT_FILE); - setGraphic(new ImageView(Icons.TRANSFORMATION_16)); - - final ObservableList items = getItems(); - descriptions.forEach(description -> items.add(new ConvertFileByConverterAction(element, description))); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java deleted file mode 100644 index d6810e9f..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ConvertFileByConverterAction.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.file.converter.FileConverterDescription; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.event.impl.RequestedConvertFileEvent; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to transformation a file by a transformer. - * - * @author JavaSaBr - */ -class ConvertFileByConverterAction extends FileAction { - - /** - * The transformer description. - */ - @NotNull - private final FileConverterDescription description; - - public ConvertFileByConverterAction(@NotNull final ResourceElement element, - @NotNull final FileConverterDescription description) { - super(element); - this.description = description; - setText(description.getDescription()); - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.TRANSFORMATION_16; - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - - final ResourceElement element = getElement(); - final RequestedConvertFileEvent newEvent = new RequestedConvertFileEvent(); - newEvent.setFile(element.getFile()); - newEvent.setDescription(description); - - FX_EVENT_MANAGER.notify(newEvent); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CopyFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CopyFileAction.java deleted file mode 100644 index 33bf2425..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CopyFileAction.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The action to copy a file. - * - * @author JavaSaBr - */ -public class CopyFileAction extends FileAction { - - @FxThread - public static void applyFor(@NotNull Array elements) { - new CopyFileAction(elements).getOnAction().handle(null); - } - - public CopyFileAction(@NotNull Array elements) { - super(elements); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_COPY_FILE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.COPY_16; - } - - @Override - @FxThread - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - - var files = getElements().stream() - .map(ResourceElement::getFile) - .collect(toArray(Path.class)); - - var clipboard = Clipboard.getSystemClipboard(); - clipboard.setContent(EditorUtil.addCopiedFile(files, new ClipboardContent())); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CutFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CutFileAction.java deleted file mode 100644 index b551b4e7..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/CutFileAction.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import static java.util.stream.Collectors.toList; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The action to cut a file. - * - * @author JavaSaBr - */ -public class CutFileAction extends FileAction { - - @FxThread - public static void applyFor(@NotNull Array elements) { - new CutFileAction(elements).getOnAction().handle(null); - } - - public CutFileAction(@NotNull Array elements) { - super(elements); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.CUT_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_CUT_FILE; - } - - @Override - @FxThread - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - - var files = getElements().stream() - .map(ResourceElement::getFile) - .map(Path::toFile) - .collect(toList()); - - var content = new ClipboardContent(); - content.putFiles(files); - content.put(EditorUtil.JAVA_PARAM, "cut"); - - var clipboard = Clipboard.getSystemClipboard(); - clipboard.setContent(content); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java deleted file mode 100644 index 29306937..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.file.delete.handler.FileDeleteHandler; -import com.ss.editor.file.delete.handler.FileDeleteHandlerFactory; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.dialog.ConfirmDialog; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The action for deleting a file. - * - * @author JavaSaBr - */ -public class DeleteFileAction extends FileAction { - - @FxThread - public static void applyFor(@NotNull Array elements) { - new DeleteFileAction(elements).getOnAction().handle(null); - } - - public DeleteFileAction(@NotNull Array elements) { - super(elements); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - - var elements = getElements(); - var first = elements.first(); - - if(elements.size() == 1) { - - var file = first.getFile(); - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null || currentAsset.equals(file)) { - return; - } - - var question = Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILE_QUESTION; - question = question.replace("%file_name%", file.getFileName().toString()); - - var confirmDialog = new ConfirmDialog(result -> handle(file, result), question); - confirmDialog.show(); - - } else { - - var question = Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_DELETE_FILES_QUESTION; - question = question.replace("%file_count%", String.valueOf(elements.size())); - - var confirmDialog = new ConfirmDialog(result -> handle(elements, result), question); - confirmDialog.show(); - } - } - - /** - * Handle the answer. - */ - private void handle(@NotNull Path file, @Nullable Boolean result) { - if (!Boolean.TRUE.equals(result)) return; - deleteFile(file); - } - - private void deleteFile(@NotNull Path file) { - var handlers = FileDeleteHandlerFactory.findFor(file); - handlers.forEach(file, FileDeleteHandler::preDelete); - FileUtils.delete(file); - handlers.forEach(file, FileDeleteHandler::postDelete); - } - - /** - * Handle the answer. - */ - private void handle(@NotNull Array elements, @Nullable Boolean result) { - - if (!Boolean.TRUE.equals(result)) { - return; - } - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) { - return; - } - - elements.stream().map(ResourceElement::getFile) - .filter(path -> !currentAsset.equals(path)) - .forEach(this::deleteFile); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/FileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/FileAction.java deleted file mode 100644 index 4bae4a02..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/FileAction.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.array.Array; -import javafx.event.ActionEvent; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of a file action. - * - * @author JavaSaBr - */ -public class FileAction extends MenuItem { - - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(FileAction.class); - - /** - * The event manager. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * The action element. - */ - @Nullable - private final ResourceElement element; - - /** - * The action elements. - */ - @Nullable - private final Array elements; - - public FileAction(@NotNull final ResourceElement element) { - this(element, null); - } - - public FileAction(@NotNull final Array elements) { - this(null, elements); - } - - public FileAction(@Nullable final ResourceElement element, @Nullable final Array elements) { - this.element = element; - this.elements = elements; - setText(getName()); - setOnAction(this::execute); - - final Image icon = getIcon(); - if (icon != null) setGraphic(new ImageView(icon)); - } - - /** - * Get the file element of this action. - * - * @return the file element. - */ - @FxThread - protected @NotNull ResourceElement getElement() { - return notNull(element); - } - - /** - * Get the file elements of this action. - * - * @return the file elements. - */ - @FxThread - protected @NotNull Array getElements() { - return notNull(elements); - } - - /** - * Get an icon of this action. - * - * @return the icon or null. - */ - @FxThread - protected @Nullable Image getIcon() { - return null; - } - - /** - * Handle executing of this action. - * - * @param event the event. - */ - @FxThread - protected void execute(@Nullable final ActionEvent event) { - } - - /** - * Get the name of this action. - * - * @return the name. - */ - @FxThread - protected @NotNull String getName() { - return "Unknown"; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ImportModelFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ImportModelFileAction.java deleted file mode 100644 index f1745665..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/ImportModelFileAction.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.FileResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.dialog.imports.model.ModelImportDialog; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to import an model to current asset folder. - * - * @author JavaSaBr - */ -public class ImportModelFileAction extends FileAction { - - public ImportModelFileAction(@NotNull final ResourceElement element) { - super(element); - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - - final ResourceElement element = getElement(); - - final ModelImportDialog dialog = new ModelImportDialog(); - if (element instanceof FileResourceElement) { - dialog.start(element.getFile().getParent()); - } else { - dialog.start(element.getFile()); - } - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_IMPORT_MODEL; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.IMPORT_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileAction.java deleted file mode 100644 index ceaae590..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileAction.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.ui.component.creator.FileCreatorRegistry; - -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import com.ss.rlib.common.util.array.Array; - -/** - * The action to create a new file. - * - * @author JavaSaBr - */ -public class NewFileAction extends Menu { - - @NotNull - private static final FileCreatorRegistry CREATOR_REGISTRY = FileCreatorRegistry.getInstance(); - - public NewFileAction(@NotNull final ResourceElement element) { - setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_NEW_FILE); - setGraphic(new ImageView(Icons.NEW_FILE_16)); - - final ObservableList items = getItems(); - - final Array descriptions = CREATOR_REGISTRY.getDescriptions(); - descriptions.forEach(description -> items.add(new NewFileByCreatorAction(element, description))); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileByCreatorAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileByCreatorAction.java deleted file mode 100644 index 238d3ede..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/NewFileByCreatorAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.ui.event.impl.RequestedCreateFileEvent; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action for creating a new file. - * - * @author JavaSaBr - */ -class NewFileByCreatorAction extends FileAction { - - /** - * The creator description. - */ - @NotNull - private final FileCreatorDescription description; - - /** - * Instantiates a new New file by creator action. - * - * @param element the element - * @param description the description - */ - NewFileByCreatorAction(@NotNull final ResourceElement element, @NotNull final FileCreatorDescription description) { - super(element); - this.description = description; - final Image icon = description.getIcon(); - setText(description.getFileDescription()); - setGraphic(new ImageView(icon == null ? Icons.NEW_FILE_16 : icon)); - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - - final RequestedCreateFileEvent newEvent = new RequestedCreateFileEvent(); - newEvent.setFile(getElement().getFile()); - newEvent.setDescription(description); - - FX_EVENT_MANAGER.notify(newEvent); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileAction.java deleted file mode 100644 index 481714b1..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileAction.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.event.impl.RequestedOpenFileEvent; -import javafx.event.ActionEvent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to open a file. - * - * @author JavaSaBr - */ -public class OpenFileAction extends FileAction { - - public OpenFileAction(@NotNull ResourceElement element) { - super(element); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE; - } - - @Override - @FxThread - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - FX_EVENT_MANAGER.notify(new RequestedOpenFileEvent(getElement().getFile())); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByEditorAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByEditorAction.java deleted file mode 100644 index 614bbaaa..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByEditorAction.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.event.impl.RequestedOpenFileEvent; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to open a file by an editor. - * - * @author JavaSaBr - */ -class OpenFileByEditorAction extends FileAction { - - /** - * The editor description. - */ - @NotNull - private final EditorDescription description; - - public OpenFileByEditorAction(@NotNull ResourceElement element, @NotNull EditorDescription description) { - super(element); - this.description = description; - - setText(description.getEditorName()); - - var icon = description.getIcon(); - - if (icon != null) { - setGraphic(new ImageView(icon)); - } - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.EDIT_16; - } - - @FxThread - @Override - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - - var newEvent = new RequestedOpenFileEvent(getElement().getFile()); - newEvent.setDescription(description); - - FX_EVENT_MANAGER.notify(newEvent); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java deleted file mode 100644 index 4fc528e7..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileByExternalEditorAction.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.util.EditorUtil; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to open a file in an external editor. - * - * @author JavaSaBr - */ -public class OpenFileByExternalEditorAction extends FileAction { - - public OpenFileByExternalEditorAction(@NotNull final ResourceElement element) { - super(element); - } - - @FxThread - @Override - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE_BY_EXTERNAL_EDITOR; - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.EDIT_2_16; - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - EditorUtil.openFileInExternalEditor(getElement().getFile()); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java deleted file mode 100644 index 8a27f265..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenFileInExplorerAction.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.util.EditorUtil; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to open a file in an system explorer. - * - * @author JavaSaBr - */ -public class OpenFileInExplorerAction extends FileAction { - - public OpenFileInExplorerAction(@NotNull final ResourceElement element) { - super(element); - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.EXPLORER_16; - } - - @FxThread - @Override - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_FILE_BY_SYSTEM_EXPLORER; - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - EditorUtil.openFileInSystemExplorer(getElement().getFile()); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenWithFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenWithFileAction.java deleted file mode 100644 index 9fd402fc..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/OpenWithFileAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.EditorRegistry; - -import org.jetbrains.annotations.NotNull; - -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import com.ss.rlib.common.util.array.Array; - -/** - * The action to choose an editor to open a file. - * - * @author JavaSaBr - */ -public class OpenWithFileAction extends Menu { - - private static final EditorRegistry EDITOR_REGISTRY = EditorRegistry.getInstance(); - - /** - * The action element. - */ - @NotNull - private final ResourceElement element; - - /** - * Instantiates a new Open with file action. - * - * @param element the element - */ - public OpenWithFileAction(@NotNull final ResourceElement element) { - this.element = element; - setText(Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_OPEN_WITH_FILE); - - final ObservableList items = getItems(); - - final Array descriptions = EDITOR_REGISTRY.getAvailableEditorsFor(element.getFile()); - descriptions.forEach(description -> items.add(new OpenFileByEditorAction(element, description))); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/PasteFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/PasteFileAction.java deleted file mode 100644 index 1638f246..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/PasteFileAction.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.event.impl.MovedFileEvent; -import com.ss.editor.ui.event.impl.RequestSelectFileEvent; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import javafx.scene.input.Clipboard; -import javafx.scene.input.DataFormat; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -/** - * The action to paste a file. - * - * @author JavaSaBr - */ -public class PasteFileAction extends FileAction { - - @FxThread - public static void applyFor(@NotNull ResourceElement element) { - new PasteFileAction(element).getOnAction().handle(null); - } - - public PasteFileAction(@NotNull ResourceElement element) { - super(element); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_PASTE_FILE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PASTE_16; - } - - @Override - @FxThread - protected void execute(@Nullable ActionEvent event) { - super.execute(event); - - var clipboard = Clipboard.getSystemClipboard(); - if (clipboard == null) { - return; - } - - List files = unsafeCast(clipboard.getContent(DataFormat.FILES)); - if (files == null || files.isEmpty()) { - return; - } - - var currentFile = getElement().getFile(); - var isCut = "cut".equals(clipboard.getContent(EditorUtil.JAVA_PARAM)); - - if (isCut) { - files.forEach(file -> moveFile(currentFile, file.toPath())); - } else { - files.forEach(file -> copyFile(currentFile, file.toPath())); - } - - clipboard.clear(); - } - - private void copyFile(@NotNull Path currentFile, @NotNull Path file) { - if (Files.isDirectory(currentFile)) { - processCopy(currentFile, file); - } else { - processCopy(currentFile.getParent(), file); - } - } - - private void moveFile(@NotNull Path currentFile, @NotNull Path file) { - if (Files.isDirectory(currentFile)) { - processMove(currentFile, file); - } else { - processMove(currentFile.getParent(), file); - } - } - - /** - * Process of moving. - */ - private void processMove(@NotNull Path targetFolder, @NotNull Path file) { - - var newFile = targetFolder.resolve(file.getFileName()); - - try { - Files.move(file, newFile); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - var event = new MovedFileEvent(); - event.setPrevFile(file); - event.setNewFile(newFile); - - FX_EVENT_MANAGER.notify(event); - } - - /** - * Process of copying. - */ - private void processCopy(@NotNull Path targetFolder, @NotNull Path file) { - - Array toCopy = ArrayFactory.newArray(Path.class); - Array copied = ArrayFactory.newArray(Path.class); - - if (Files.isDirectory(file)) { - toCopy.addAll(FileUtils.getFiles(file, true)); - toCopy.sort(FileUtils.FILE_PATH_LENGTH_COMPARATOR); - toCopy.slowRemove(file); - } - - var freeName = FileUtils.getFirstFreeName(targetFolder, file); - var newFile = targetFolder.resolve(freeName); - - try { - processCopy(file, toCopy, copied, newFile); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - } - - var event = new RequestSelectFileEvent(); - event.setFile(newFile); - - FX_EVENT_MANAGER.notify(event); - } - - /** - * Process of copying. - */ - private void processCopy( - @NotNull Path file, - @NotNull Array toCopy, - @NotNull Array copied, - @NotNull Path newFile - ) throws IOException { - - Files.copy(file, newFile); - - copied.add(newFile); - toCopy.forEach(path -> { - - var relativeFile = file.relativize(path); - var targetFile = newFile.resolve(relativeFile); - - try { - Files.copy(path, targetFile); - } catch (final IOException e) { - throw new RuntimeException(e); - } - - var needAddToCopied = true; - - for (var copiedFile : copied) { - - if (!Files.isDirectory(copiedFile)) { - continue; - } - - if (targetFile.startsWith(copiedFile)) { - needAddToCopied = false; - break; - } - } - - if (needAddToCopied) { - copied.add(targetFile); - } - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/RenameFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/RenameFileAction.java deleted file mode 100644 index 8805b2ca..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/RenameFileAction.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.action; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.dialog.RenameDialog; -import com.ss.editor.ui.event.impl.RenamedFileEvent; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.event.ActionEvent; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The action to rename a file. - * - * @author JavaSaBr - */ -public class RenameFileAction extends FileAction { - - public RenameFileAction(@NotNull final ResourceElement element) { - super(element); - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.EDIT_16; - } - - @FxThread - @Override - protected @NotNull String getName() { - return Messages.ASSET_COMPONENT_RESOURCE_TREE_CONTEXT_MENU_RENAME_FILE; - } - - @FxThread - @Override - protected void execute(@Nullable final ActionEvent event) { - super.execute(event); - - final Path file = getElement().getFile(); - - final RenameDialog renameDialog = new RenameDialog(); - renameDialog.setValidator(this::checkName); - renameDialog.setHandler(this::processRename); - renameDialog.setInitName(FileUtils.getNameWithoutExtension(file)); - renameDialog.show(); - } - - /** - * The checking of the new file name. - */ - private Boolean checkName(@NotNull final String newFileName) { - if (!FileUtils.isValidName(newFileName)) return false; - - final Path file = getElement().getFile(); - final String extension = FileUtils.getExtension(file); - - final Path parent = file.getParent(); - final Path targetFile = parent.resolve(StringUtils.isEmpty(extension) ? newFileName : newFileName + "." + extension); - - return !Files.exists(targetFile); - } - - /** - * The process of renaming. - */ - private void processRename(@NotNull final String newFileName) { - - final Path file = getElement().getFile(); - - final String extension = FileUtils.getExtension(file); - final String resultName = StringUtils.isEmpty(extension) ? newFileName : newFileName + "." + extension; - - final Path newFile = file.resolveSibling(resultName); - - try { - Files.move(file, newFile); - } catch (final IOException e) { - EditorUtil.handleException(null, this, e); - return; - } - - final RenamedFileEvent event = new RenamedFileEvent(); - event.setNewFile(newFile); - event.setPrevFile(file); - - FX_EVENT_MANAGER.notify(event); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java deleted file mode 100644 index ed07549b..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeMultiContextMenuFiller.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.filler; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.control.MenuItem; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.function.Predicate; - -/** - * The interface to implement a context menu filler for multiply elements. - * - * @author JavaSaBr - */ -@FunctionalInterface -public interface AssetTreeMultiContextMenuFiller { - - /** - * Fill the context menu of the resource element. - * - * @param elements the list of resource elements. - * @param items the container of items of a context menu. - * @param actionTester the action tester. - */ - @FxThread - void fill(@NotNull final Array elements, @NotNull final List items, - @NotNull final Predicate> actionTester); -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java deleted file mode 100644 index c7acf851..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/AssetTreeSingleContextMenuFiller.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.filler; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import javafx.scene.control.MenuItem; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.function.Predicate; - -/** - * The interface to implement a context menu filler. - * - * @author JavaSaBr - */ -@FunctionalInterface -public interface AssetTreeSingleContextMenuFiller { - - /** - * Fill the context menu of the resource element. - * - * @param element the resource element. - * @param items the container of items of a context menu. - * @param actionTester the action tester. - */ - @FxThread - void fill(@NotNull final ResourceElement element, @NotNull final List items, - @NotNull final Predicate> actionTester); -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java deleted file mode 100644 index 34046b41..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/filler/impl/FileAssetTreeSingleContextMenuFiller.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.context.menu.filler.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.file.converter.FileConverterDescription; -import com.ss.editor.file.converter.FileConverterRegistry; -import com.ss.editor.ui.component.asset.tree.context.menu.action.*; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeMultiContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.context.menu.filler.AssetTreeSingleContextMenuFiller; -import com.ss.editor.ui.component.asset.tree.resource.FileResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.control.MenuItem; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.util.List; -import java.util.function.Predicate; - -/** - * The implementation a filler to create actions for files. - * - * @author JavaSaBr - */ -public class FileAssetTreeSingleContextMenuFiller implements AssetTreeSingleContextMenuFiller, - AssetTreeMultiContextMenuFiller { - - @NotNull - private static final FileConverterRegistry FILE_CONVERTER_REGISTRY = FileConverterRegistry.getInstance(); - - @Override - @FxThread - public void fill(@NotNull final ResourceElement element, @NotNull final List items, - @NotNull final Predicate> actionTester) { - - if (element instanceof FileResourceElement) { - - if (actionTester.test(OpenFileAction.class)) { - items.add(new OpenFileAction(element)); - } - - if (actionTester.test(OpenWithFileAction.class)) { - items.add(new OpenWithFileAction(element)); - } - - - if (actionTester.test(ConvertFileAction.class)) { - - final Path file = element.getFile(); - final Array descriptions = FILE_CONVERTER_REGISTRY.getDescriptions(file); - - if (!descriptions.isEmpty()) { - items.add(new ConvertFileAction(element, descriptions)); - } - } - - if (actionTester.test(OpenFileByExternalEditorAction.class)) { - items.add(new OpenFileByExternalEditorAction(element)); - } - } - } - - @Override - @FxThread - public void fill(@NotNull final Array elements, @NotNull final List items, - @NotNull final Predicate> actionTester) { - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ImageResourceElement.java b/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ImageResourceElement.java deleted file mode 100644 index 23ace858..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ImageResourceElement.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.resource; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.tooltip.ImagePreview; -import javafx.scene.control.Tooltip; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The presentation of an image. - * - * @author JavaSaBr - */ -public class ImageResourceElement extends FileResourceElement { - - public ImageResourceElement(@NotNull final Path file) { - super(file); - } - - @Override - @FxThread - public @Nullable Tooltip createToolTip() { - return new ImagePreview(getFile()); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ResourceElementFactory.java b/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ResourceElementFactory.java deleted file mode 100644 index 7f8c65e8..00000000 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/resource/ResourceElementFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.component.asset.tree.resource; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.JavaFxImageManager; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The factory to create resource elements. - * - * @author JavaSaBr - */ -public class ResourceElementFactory { - - /** - * Create a resource element for the file. - * - * @param file the file. - * @return the created resource element. - */ - @FromAnyThread - public static @NotNull ResourceElement createFor(@NotNull final Path file) { - if (Files.isDirectory(file)) { - return new FolderResourceElement(file); - } else if (JavaFxImageManager.isImage(file)) { - return new ImageResourceElement(file); - } else { - return new FileResourceElement(file); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/AboutAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/AboutAction.java deleted file mode 100644 index aeea233d..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/AboutAction.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import com.ss.editor.Messages; -import com.ss.editor.ui.dialog.about.AboutDialog; -import javafx.scene.control.MenuItem; - -/** - * The action to open the About dialog. - * - * @author JavaSaBr - */ -public class AboutAction extends MenuItem { - - /** - * Instantiates a new AboutAction. - */ - public AboutAction() { - super(Messages.EDITOR_MENU_HELP_ABOUT); - setOnAction(event -> process()); - } - - /** - * Open the dialog. - */ - private void process() { - final AboutDialog dialog = new AboutDialog(); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/ClearAssetCacheAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/ClearAssetCacheAction.java deleted file mode 100644 index daa8d0f3..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/ClearAssetCacheAction.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import com.jme3.asset.AssetManager; -import com.ss.editor.Messages; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.util.EditorUtil; -import javafx.scene.control.MenuItem; - -/** - * The action to clean asset cache. - * - * @author JavaSaBr - */ -public class ClearAssetCacheAction extends MenuItem { - - /** - * Instantiates a new ClearAssetCacheAction. - */ - public ClearAssetCacheAction() { - super(Messages.EDITOR_MENU_OTHER_CLEAR_ASSET_CACHE); - setOnAction(event -> process()); - } - - /** - * Clear asset cache. - */ - private void process() { - ExecutorManager.getInstance().addJmeTask(() -> { - final AssetManager assetManager = EditorUtil.getAssetManager(); - assetManager.clearCache(); - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/OpenAssetAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/OpenAssetAction.java deleted file mode 100644 index afb89d2a..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/OpenAssetAction.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_NATIVE_FILE_CHOOSER; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_NATIVE_FILE_CHOOSER; -import com.ss.editor.Messages; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.dialog.file.chooser.OpenExternalFolderEditorDialog; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.ChangedCurrentAssetFolderEvent; -import com.ss.editor.util.EditorUtil; -import javafx.scene.control.MenuItem; -import javafx.stage.DirectoryChooser; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The action to open a new asset folder. - * - * @author JavaSaBr - */ -public class OpenAssetAction extends MenuItem { - - @NotNull - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - public OpenAssetAction() { - super(Messages.EDITOR_MENU_FILE_OPEN_ASSET); - setOnAction(event -> process()); - } - - /** - * The process of selecting an asset folder. - */ - @FxThread - private void process() { - - final EditorConfig config = EditorConfig.getInstance(); - - if (config.getBoolean(PREF_NATIVE_FILE_CHOOSER, PREF_DEFAULT_NATIVE_FILE_CHOOSER)) { - openAssetByNative(); - } else { - openAsset(); - } - } - - /** - * Open asset folder using native file chooser. - */ - @FxThread - private void openAssetByNative() { - - final DirectoryChooser chooser = new DirectoryChooser(); - chooser.setTitle(Messages.EDITOR_MENU_FILE_OPEN_ASSET_DIRECTORY_CHOOSER); - - final EditorConfig config = EditorConfig.getInstance(); - final Path currentAsset = config.getCurrentAsset(); - final File currentFolder = currentAsset == null ? null : currentAsset.toFile(); - - if (currentFolder == null) { - chooser.setInitialDirectory(new File(System.getProperty("user.home"))); - } else { - chooser.setInitialDirectory(currentFolder); - } - - GAnalytics.sendPageView("AssetChooseDialog", null, "/dialog/AssetChooseDialog"); - GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_OPENED, "AssetChooseDialog"); - - final File folder = chooser.showDialog(EditorUtil.getFxLastWindow()); - - GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_CLOSED, "AssetChooseDialog"); - - if (folder == null) { - return; - } - - openAssetFolder(folder.toPath()); - } - - /** - * Open an asset folder using custom file chooser. - */ - @FxThread - private void openAsset() { - - final OpenExternalFolderEditorDialog dialog = new OpenExternalFolderEditorDialog(this::openAssetFolder); - dialog.setTitleText(Messages.EDITOR_MENU_FILE_OPEN_ASSET_DIRECTORY_CHOOSER); - - final EditorConfig config = EditorConfig.getInstance(); - final Path currentAsset = config.getCurrentAsset(); - - if (currentAsset == null) { - dialog.setInitDirectory(Paths.get(System.getProperty("user.home"))); - } else { - dialog.setInitDirectory(currentAsset); - } - - dialog.show(); - } - - /** - * Open the asset folder. - * - * @param newAsset the asset folder. - */ - @FxThread - public void openAssetFolder(@NotNull final Path newAsset) { - - final EditorConfig config = EditorConfig.getInstance(); - final Path currentAsset = config.getCurrentAsset(); - if (newAsset.equals(currentAsset)) return; - - config.addOpenedAsset(newAsset); - config.setCurrentAsset(newAsset); - config.save(); - - FX_EVENT_MANAGER.notify(new ChangedCurrentAssetFolderEvent(newAsset)); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/OpenPluginsAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/OpenPluginsAction.java deleted file mode 100644 index 481d5e09..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/OpenPluginsAction.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import com.ss.editor.Messages; -import com.ss.editor.ui.dialog.plugin.PluginsDialog; -import javafx.scene.control.MenuItem; - -/** - * The action to open plugins dialog. - * - * @author JavaSaBr - */ -public class OpenPluginsAction extends MenuItem { - - public OpenPluginsAction() { - super(Messages.EDITOR_MENU_OTHER_PLUGINS); - setOnAction(event -> process()); - } - - /** - * Open the plugin dialog. - */ - private void process() { - final PluginsDialog dialog = new PluginsDialog(); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/OpenSettingsAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/OpenSettingsAction.java deleted file mode 100644 index c6269dd6..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/OpenSettingsAction.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import com.ss.editor.Messages; -import com.ss.editor.ui.dialog.SettingsDialog; -import javafx.scene.control.MenuItem; - -/** - * The action to open the dialog with settings. - * - * @author JavaSaBr - */ -public class OpenSettingsAction extends MenuItem { - - /** - * Instantiates a new OpenSettingsAction. - */ - public OpenSettingsAction() { - super(Messages.EDITOR_MENU_OTHER_SETTINGS); - setOnAction(event -> process()); - } - - /** - * Open the dialog. - */ - private void process() { - final SettingsDialog dialog = new SettingsDialog(); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/bar/action/UpdateClasspathAndAssetCacheAction.java b/src/main/java/com/ss/editor/ui/component/bar/action/UpdateClasspathAndAssetCacheAction.java deleted file mode 100644 index 9002cc9c..00000000 --- a/src/main/java/com/ss/editor/ui/component/bar/action/UpdateClasspathAndAssetCacheAction.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ss.editor.ui.component.bar.action; - -import com.jme3.asset.AssetManager; -import com.ss.editor.Messages; -import com.ss.editor.manager.ClasspathManager; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.util.EditorUtil; -import javafx.scene.control.MenuItem; - -/** - * The action to update a user classpath and to clear asset cache. - * - * @author JavaSaBr - */ -public class UpdateClasspathAndAssetCacheAction extends MenuItem { - - /** - * Instantiates a new UpdateClasspathAndAssetCacheAction. - */ - public UpdateClasspathAndAssetCacheAction() { - super(Messages.EDITOR_MENU_OTHER_UPDATE_CLASSPATH_AND_ASSET_CACHE); - setOnAction(event -> process()); - } - - /** - * Update classpath and clear asset cache. - */ - private void process() { - ExecutorManager.getInstance().addJmeTask(() -> { - - final ClasspathManager classpathManager = ClasspathManager.getInstance(); - classpathManager.reload(); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - assetManager.clearCache(); - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/FileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/FileCreator.java deleted file mode 100644 index 917f9fee..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/FileCreator.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ss.editor.ui.component.creator; - -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The interface to implement a some file creator. - * - * @author JavaSaBr - */ -public interface FileCreator { - - /** - * Start creating near the file. - * - * @param file the file. - */ - void start(@NotNull final Path file); -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorDescription.java b/src/main/java/com/ss/editor/ui/component/creator/FileCreatorDescription.java deleted file mode 100644 index 47dc1000..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorDescription.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.ss.editor.ui.component.creator; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.Callable; - -/** - * The description of a file creator. - * - * @author JavaSaBr - */ -public class FileCreatorDescription { - - /** - * The file description. - */ - @Nullable - private String fileDescription; - - /** - * The constructor of a file creator. - */ - @Nullable - private Callable constructor; - - /** - * The icon. - */ - @Nullable - private Image icon; - - /** - * Sets constructor. - * - * @param constructor the constructor of a file creator. - */ - public void setConstructor(@NotNull final Callable constructor) { - this.constructor = constructor; - } - - /** - * Sets file description. - * - * @param fileDescription the file description. - */ - public void setFileDescription(@NotNull final String fileDescription) { - this.fileDescription = fileDescription; - } - - /** - * Gets constructor. - * - * @return the constructor of a file creator. - */ - @NotNull - public Callable getConstructor() { - return notNull(constructor); - } - - /** - * Gets file description. - * - * @return the file description. - */ - @NotNull - public String getFileDescription() { - return notNull(fileDescription); - } - - /** - * Sets icon. - * - * @param icon the icon. - */ - public void setIcon(@Nullable final Image icon) { - this.icon = icon; - } - - /** - * Gets icon. - * - * @return the icon. - */ - @Nullable - public Image getIcon() { - return icon; - } - - @Override - public String toString() { - return "FileCreatorDescription{" + - "fileDescription='" + fileDescription + '\'' + - ", constructor=" + constructor + - '}'; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java b/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java deleted file mode 100644 index 4c8f3a9d..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.ss.editor.ui.component.creator; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.creator.impl.*; -import com.ss.editor.ui.component.creator.impl.material.MaterialFileCreator; -import com.ss.editor.ui.component.creator.impl.material.definition.MaterialDefinitionFileCreator; -import com.ss.editor.ui.component.creator.impl.texture.SingleColorTextureFileCreator; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.concurrent.Callable; - -/** - * The registry with file creators. - * - * @author JavaSaBr - */ -public class FileCreatorRegistry { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(FileCreatorRegistry.class); - - @NotNull - private static final FileCreatorRegistry INSTANCE = new FileCreatorRegistry(); - - /** - * Gets instance. - * - * @return the instance - */ - @NotNull - public static FileCreatorRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of file creator descriptions. - */ - @NotNull - private final Array descriptions; - - /** - * Instantiates a new File creator registry. - */ - private FileCreatorRegistry() { - this.descriptions = ArrayFactory.newArray(FileCreatorDescription.class); - register(MaterialFileCreator.DESCRIPTION); - register(MaterialDefinitionFileCreator.DESCRIPTION); - register(EmptyFileCreator.DESCRIPTION); - register(FolderCreator.DESCRIPTION); - register(EmptyModelCreator.DESCRIPTION); - register(SingleColorTextureFileCreator.DESCRIPTION); - register(EmptySceneCreator.DESCRIPTION); - } - - /** - * Add a new creator description. - * - * @param description the new description. - */ - @FromAnyThread - public void register(@NotNull final FileCreatorDescription description) { - this.descriptions.add(description); - } - - /** - * Gets descriptions. - * - * @return the list of file creator descriptions. - */ - @NotNull - public Array getDescriptions() { - return descriptions; - } - - /** - * Create a new creator of the description for the file. - * - * @param description the file creator description. - * @param file the file. - * @return the file creator. - */ - @Nullable - public FileCreator newCreator(@NotNull final FileCreatorDescription description, @NotNull final Path file) { - - final Callable constructor = description.getConstructor(); - try { - return constructor.call(); - } catch (final Exception e) { - LOGGER.warning(e); - } - - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/AbstractFileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/AbstractFileCreator.java deleted file mode 100644 index 97e3dc42..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/AbstractFileCreator.java +++ /dev/null @@ -1,409 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.component.asset.tree.ResourceTree; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.component.creator.FileCreator; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.RequestSelectFileEvent; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.Utils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.*; -import javafx.scene.control.TextField; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.io.IOException; -import java.nio.file.AtomicMoveNotSupportedException; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The base implementation of a file creator. - * - * @author JavaSaBr - */ -public abstract class AbstractFileCreator extends AbstractSimpleEditorDialog implements FileCreator { - - /** - * The constant LOGGER. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(FileCreator.class); - - /** - * The constant DIALOG_SIZE. - */ - @NotNull - protected static final Point DIALOG_SIZE = new Point(900, -1); - - /** - * The constant EXECUTOR_MANAGER. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The constant FX_EVENT_MANAGER. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * The resources tree. - */ - @Nullable - private ResourceTree resourceTree; - - /** - * The preview container. - */ - @Nullable - private BorderPane previewContainer; - - /** - * The filed with new file name. - */ - @Nullable - private TextField fileNameField; - - /** - * The init file. - */ - @Nullable - private Path initFile; - - @Override - public void start(@NotNull final Path file) { - this.initFile = file; - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Path currentAsset = notNull(editorConfig.getCurrentAsset()); - - show(); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.setOnLoadHandler(finished -> expand(file, resourceTree, finished)); - resourceTree.fill(currentAsset); - - EXECUTOR_MANAGER.addFxTask(getFileNameField()::requestFocus); - - validateFileName(); - } - - @FxThread - private void expand(@NotNull final Path file, @NotNull final ResourceTree resourceTree, - @NotNull final Boolean finished) { - if (finished) resourceTree.expandTo(file, true); - } - - /** - * @return the resources tree. - */ - @FromAnyThread - private @NotNull ResourceTree getResourceTree() { - return notNull(resourceTree); - } - - /** - * @param initFile the init file. - */ - @FromAnyThread - private void setInitFile(@NotNull final Path initFile) { - this.initFile = initFile; - } - - /** - * @return the init file. - */ - @FromAnyThread - private @NotNull Path getInitFile() { - return notNull(initFile); - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_CREATE; - } - - /** - * @return the selected file in the resources tree. - */ - @FromAnyThread - private @NotNull Path getSelectedFile() { - - final ResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - final TreeItem selectedItem = selectionModel.getSelectedItem(); - if (selectedItem == null) return getInitFile(); - - final ResourceElement element = selectedItem.getValue(); - return element.getFile(); - } - - /** - * Gets file to create. - * - * @return the file to creating. - */ - @FromAnyThread - protected @Nullable Path getFileToCreate() { - - final TextField fileNameField = getFileNameField(); - final String filename = fileNameField.getText(); - if (StringUtils.isEmpty(filename)) return null; - - final String fileExtension = getFileExtension(); - - final Path selectedFile = getSelectedFile(); - final Path directory = Files.isDirectory(selectedFile) ? selectedFile : selectedFile.getParent(); - - return StringUtils.isEmpty(fileExtension) ? directory.resolve(filename) : - directory.resolve(filename + "." + fileExtension); - } - - /** - * Gets file extension. - * - * @return the file extension. - */ - @FromAnyThread - protected @NotNull String getFileExtension() { - return StringUtils.EMPTY; - } - - @Override - @FxThread - protected void processOk() { - super.processOk(); - - UiUtils.incrementLoading(); - - EXECUTOR_MANAGER.addBackgroundTask(() -> { - - final Path tempFile; - try { - tempFile = Files.createTempFile("SSEditor", "fileCreator"); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); - return; - } - - final Path fileToCreate = notNull(getFileToCreate()); - try { - - writeData(tempFile); - try { - Files.move(tempFile, fileToCreate, REPLACE_EXISTING, ATOMIC_MOVE); - } catch (final AtomicMoveNotSupportedException ex) { - Files.move(tempFile, fileToCreate, REPLACE_EXISTING); - } - - notifyFileCreated(fileToCreate, true); - - } catch (final Exception e) { - Utils.run(tempFile, Files::delete); - EditorUtil.handleException(LOGGER, this, e); - } - - EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); - }); - } - - /** - * Write created data to the created file. - * - * @param resultFile the result file. - * @throws IOException if was some problem with writing to the result file. - */ - @BackgroundThread - protected void writeData(@NotNull final Path resultFile) throws IOException { - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - super.createContent(root); - - final HBox container = new HBox(); - container.prefWidthProperty().bind(widthProperty()); - - final GridPane settingsContainer = new GridPane(); - settingsContainer.prefWidthProperty().bind(container.widthProperty().multiply(0.5)); - - resourceTree = new ResourceTree(null, true); - resourceTree.prefWidthProperty().bind(container.widthProperty().multiply(0.5)); - - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - selectionModel.selectedItemProperty().addListener((observable, oldValue, newValue) -> validateFileName()); - - createSettings(settingsContainer); - - FXUtils.addToPane(resourceTree, container); - - if (needPreview()) { - - final VBox wrapper = new VBox(); - - previewContainer = new BorderPane(); - - settingsContainer.prefHeightProperty().bind(container.heightProperty() - .subtract(previewContainer.heightProperty())); - - createPreview(previewContainer); - - FXUtils.bindFixedWidth(previewContainer, wrapper.widthProperty()); - FXUtils.bindFixedHeight(previewContainer, wrapper.widthProperty()); - - FXUtils.addToPane(settingsContainer, wrapper); - FXUtils.addToPane(previewContainer, wrapper); - FXUtils.addToPane(wrapper, container); - - FXUtils.addClassTo(wrapper, CssClasses.DEF_VBOX); - FXUtils.addClassTo(previewContainer, CssClasses.DEF_BORDER_PANE); - - } else { - settingsContainer.prefHeightProperty().bind(container.heightProperty()); - FXUtils.addToPane(settingsContainer, container); - } - - FXUtils.addToPane(container, root); - - FXUtils.addClassTo(root, CssClasses.FILE_CREATOR_DIALOG); - FXUtils.addClassTo(container, CssClasses.DEF_HBOX); - FXUtils.addClassTo(settingsContainer, CssClasses.DEF_GRID_PANE); - } - - /** - * Notify about the file created. - * - * @param createdFile the created file - * @param needSelect the need select - */ - @FromAnyThread - protected void notifyFileCreated(@NotNull final Path createdFile, final boolean needSelect) { - if (!needSelect) return; - - final RequestSelectFileEvent event = new RequestSelectFileEvent(); - event.setFile(createdFile); - - FX_EVENT_MANAGER.notify(event); - } - - /** - * If return true the creator will create {@link #previewContainer}. - * - * @return true if need to create preview container. - */ - @FromAnyThread - protected boolean needPreview() { - return false; - } - - /** - * @return the preview container. - */ - @FromAnyThread - protected @Nullable BorderPane getPreviewContainer() { - return previewContainer; - } - - /** - * Create preview. - * - * @param container the preview container. - */ - @FxThread - protected void createPreview(@NotNull final BorderPane container) { - } - - /** - * @return the filed with new file name. - */ - @FromAnyThread - protected @NotNull TextField getFileNameField() { - return notNull(fileNameField); - } - - /** - * Create settings of the creating file. - * - * @param root the root - */ - @FxThread - protected void createSettings(@NotNull final GridPane root) { - - final Label fileNameLabel = new Label(getFileNameLabelText() + ":"); - fileNameLabel.prefWidthProperty().bind(root.widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); - - fileNameField = new TextField(); - fileNameField.prefWidthProperty().bind(root.widthProperty()); - fileNameField.textProperty().addListener((observable, oldValue, newValue) -> validateFileName()); - fileNameField.prefWidthProperty().bind(root.widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - root.add(fileNameLabel, 0, 0); - root.add(fileNameField, 1, 0); - - FXUtils.addClassTo(fileNameLabel, CssClasses.DIALOG_DYNAMIC_LABEL); - FXUtils.addClassTo(fileNameField, CssClasses.DIALOG_FIELD); - } - - /** - * Gets file name label text. - * - * @return the label text "file name". - */ - @FromAnyThread - protected @NotNull String getFileNameLabelText() { - return Messages.FILE_CREATOR_FILE_NAME_LABEL; - } - - /** - * Validate the inputted name. - */ - @FxThread - protected void validateFileName() { - - final Button okButton = getOkButton(); - if (okButton == null) return; - - final Path fileToCreate = getFileToCreate(); - - if (fileToCreate == null || Files.exists(fileToCreate)) { - okButton.setDisable(true); - return; - } - - okButton.setDisable(false); - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyFileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyFileCreator.java deleted file mode 100644 index fa1f24aa..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyFileCreator.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.rlib.common.util.StringUtils; -import org.jetbrains.annotations.NotNull; - -/** - * The creator to create an empty file. - * - * @author JavaSaBr - */ -public class EmptyFileCreator extends AbstractFileCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - static { - DESCRIPTION.setFileDescription(Messages.EMPTY_FILE_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(EmptyFileCreator::new); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.EMPTY_FILE_CREATOR_TITLE; - } - - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return StringUtils.EMPTY; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyModelCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyModelCreator.java deleted file mode 100644 index d216070a..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptyModelCreator.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import static java.nio.file.StandardOpenOption.WRITE; -import com.jme3.export.binary.BinaryExporter; -import com.jme3.scene.Node; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The creator to create an empty model. - * - * @author JavaSaBr - */ -public class EmptyModelCreator extends AbstractFileCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - static { - DESCRIPTION.setFileDescription(Messages.EMPTY_MODEL_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(EmptyModelCreator::new); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.EMPTY_MODEL_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return FileExtensions.JME_OBJECT; - } - - @Override - @BackgroundThread - protected void writeData(@NotNull final Path resultFile) throws IOException { - super.writeData(resultFile); - - final BinaryExporter exporter = BinaryExporter.getInstance(); - final Node newNode = new Node("Model root"); - - try (final OutputStream out = Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - exporter.save(newNode, out); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptySceneCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/EmptySceneCreator.java deleted file mode 100644 index a0d7ba3b..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/EmptySceneCreator.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import static java.nio.file.StandardOpenOption.WRITE; -import com.jme3.export.binary.BinaryExporter; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The creator for creating an empty scene. - * - * @author JavaSaBr - */ -public class EmptySceneCreator extends AbstractFileCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - static { - DESCRIPTION.setFileDescription(Messages.EMPTY_SCENE_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(EmptySceneCreator::new); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.EMPTY_SCENE_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return FileExtensions.JME_SCENE; - } - - @Override - @BackgroundThread - protected void writeData(@NotNull final Path resultFile) throws IOException { - super.writeData(resultFile); - - final BinaryExporter exporter = BinaryExporter.getInstance(); - final SceneNode newNode = createScene(); - - try (final OutputStream out = Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - exporter.save(newNode, out); - } - } - - /** - * Create scene scene node. - * - * @return the scene node - */ - @FxThread - protected @NotNull SceneNode createScene() { - final SceneNode newNode = new SceneNode(); - newNode.addLayer(new SceneLayer("Default", true)); - newNode.addLayer(new SceneLayer("TransparentFX", true)); - newNode.addLayer(new SceneLayer("Ignore Raycast", true)); - newNode.addLayer(new SceneLayer("Water", true)); - newNode.getLayers().forEach(SceneLayer::show); - return newNode; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/FolderCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/FolderCreator.java deleted file mode 100644 index 8d4d52ae..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/FolderCreator.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; -import com.ss.rlib.common.util.StringUtils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The creator to create a folder. - * - * @author JavaSaBr - */ -public class FolderCreator extends AbstractFileCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - static { - DESCRIPTION.setFileDescription(Messages.FOLDER_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(FolderCreator::new); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.FOLDER_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return StringUtils.EMPTY; - } - - @Override - @FromAnyThread - protected @NotNull String getFileNameLabelText() { - return Messages.FOLDER_CREATOR_FILE_NAME_LABEL; - } - - @Override - @FxThread - protected void processOk() { - super.hide(); - - final Path fileToCreate = notNull(getFileToCreate()); - try { - Files.createDirectory(fileToCreate); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - notifyFileCreated(fileToCreate, true); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/material/MaterialFileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/material/MaterialFileCreator.java deleted file mode 100644 index d828abb0..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/material/MaterialFileCreator.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.ss.editor.ui.component.creator.impl.material; - -import static com.ss.editor.FileExtensions.JME_MATERIAL; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.nio.file.StandardOpenOption.*; -import com.jme3.material.Material; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditablePropertyType; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.plugin.api.file.creator.GenericFileCreator; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.MaterialSerializer; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The creator to create a new material. - * - * @author JavaSaBr - */ -public class MaterialFileCreator extends GenericFileCreator { - - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - private static final ResourceManager RESOURCE_MANAGER = ResourceManager.getInstance(); - - private static final String PBR_MAT_DEF = "Common/MatDefs/Light/PBRLighting.j3md"; - private static final String LIGHTING_MAT_DEF = "Common/MatDefs/Light/Lighting.j3md"; - private static final String PROP_MAT_DEF = "matDef"; - - static { - DESCRIPTION.setFileDescription(Messages.MATERIAL_FILE_CREATOR_FILE_DESCRIPTION); - DESCRIPTION.setConstructor(MaterialFileCreator::new); - } - - /** - * The list of available definitions. - */ - @Nullable - private Array definitions; - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.MATERIAL_FILE_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return JME_MATERIAL; - } - - @Override - @FromAnyThread - protected @NotNull Array getPropertyDefinitions() { - - definitions = RESOURCE_MANAGER.getAvailableResources(FileExtensions.JME_MATERIAL_DEFINITION); - - String def; - - if (definitions.contains(PBR_MAT_DEF)) { - def = PBR_MAT_DEF; - } else if (definitions.contains(LIGHTING_MAT_DEF)) { - def = LIGHTING_MAT_DEF; - } else { - def = definitions.first(); - } - - var result = ArrayFactory.newArray(PropertyDefinition.class); - result.add(new PropertyDefinition(EditablePropertyType.STRING_FROM_LIST, - Messages.MATERIAL_FILE_CREATOR_MATERIAL_TYPE_LABEL, PROP_MAT_DEF, def, definitions)); - - return result; - } - - /** - * Get the list of available definitions. - * - * @return the list of available definitions. - */ - @FromAnyThread - private @NotNull Array getDefinitions() { - return notNull(definitions); - } - - @Override - @FxThread - protected boolean validate(@NotNull VarTable vars) { - - var matDef = vars.get(PROP_MAT_DEF, String.class, StringUtils.EMPTY); - - if (matDef.isEmpty() || !getDefinitions().contains(matDef)) { - return false; - } - - return super.validate(vars); - } - - @Override - @BackgroundThread - protected void writeData(@NotNull VarTable vars, @NotNull Path resultFile) throws IOException { - super.writeData(vars, resultFile); - - var assetManager = EditorUtil.getAssetManager(); - var matDef = vars.get(PROP_MAT_DEF, String.class); - - var material = new Material(assetManager, matDef); - material.getAdditionalRenderState(); - - var materialContent = MaterialSerializer.serializeToString(material); - - try (var out = new PrintWriter(Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE))) { - out.print(materialContent); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java deleted file mode 100644 index 68a3555f..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/material/definition/MaterialDefinitionFileCreator.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.ss.editor.ui.component.creator.impl.material.definition; - -import static com.ss.editor.FileExtensions.JME_MATERIAL_DEFINITION; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.lang.Character.toUpperCase; -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import static java.nio.file.StandardOpenOption.WRITE; -import com.jme3.material.TechniqueDef; -import com.jme3.renderer.Caps; -import com.jme3.renderer.Renderer; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.extension.property.EditablePropertyType; -import com.ss.editor.plugin.api.file.creator.GenericFileCreator; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.component.creator.FileCreator; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.EnumSet; - -/** - * The creator to create a new material definition. - * - * @author JavaSaBr - */ -public class MaterialDefinitionFileCreator extends GenericFileCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - @NotNull - private static final String PROP_GLSL_VERSION = "glslVersion"; - - static { - DESCRIPTION.setFileDescription(Messages.MATERIAL_DEFINITION_FILE_CREATOR_FILE_DESCRIPTION); - DESCRIPTION.setConstructor(MaterialDefinitionFileCreator::new); - } - - @NotNull - private static final Array AVAILABLE_GLSL; - - static { - AVAILABLE_GLSL = ArrayFactory.newArray(String.class); - - final Renderer renderer = EditorUtil.getRenderer(); - final EnumSet caps = renderer.getCaps(); - caps.stream().filter(cap -> cap.name().startsWith("GLSL")) - .map(Enum::name) - .sorted(StringUtils::compareIgnoreCase) - .forEach(AVAILABLE_GLSL::add); - } - - @NotNull - private static final String MD_TEMPLATE; - - @NotNull - private static final String FRAG_TEMPLATE; - - @NotNull - private static final String VERT_TEMPLATE; - - static { - final InputStream mdResource = FileCreator.class.getResourceAsStream("/template/matdef/empty.j3md"); - final InputStream fragResource = FileCreator.class.getResourceAsStream("/template/frag/empty.frag"); - final InputStream vertResource = FileCreator.class.getResourceAsStream("/template/vert/empty.vert"); - MD_TEMPLATE = FileUtils.read(mdResource); - FRAG_TEMPLATE = FileUtils.read(fragResource); - VERT_TEMPLATE = FileUtils.read(vertResource); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.MATERIAL_DEFINITION_FILE_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return JME_MATERIAL_DEFINITION; - } - - @Override - @FxThread - protected boolean validate(@NotNull final VarTable vars) { - - final String glslVersion = vars.get(PROP_GLSL_VERSION, String.class, StringUtils.EMPTY); - - if (glslVersion.isEmpty() || !AVAILABLE_GLSL.contains(glslVersion)) { - return false; - } - - return super.validate(vars); - } - - @Override - @FromAnyThread - protected @NotNull Array getPropertyDefinitions() { - - final Array result = ArrayFactory.newArray(PropertyDefinition.class); - result.add(new PropertyDefinition(EditablePropertyType.STRING_FROM_LIST, - Messages.MATERIAL_DEFINITION_FILE_CREATOR_GLSL_LABEL, PROP_GLSL_VERSION, Caps.GLSL150.name(), AVAILABLE_GLSL)); - - return result; - } - - @Override - @FxThread - protected void processOk() { - super.hide(); - - final Path matDefFile = notNull(getFileToCreate()); - final String filename = FileUtils.getNameWithoutExtension(matDefFile); - - final Path parent = matDefFile.getParent(); - final Path fragmentFile = parent.resolve(filename + "." + FileExtensions.GLSL_FRAGMENT); - final Path vertexFile = parent.resolve(filename + "." + FileExtensions.GLSL_VERTEX); - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Path assetFolder = notNull(editorConfig.getCurrentAsset()); - - final Path pathToFragment = assetFolder.relativize(fragmentFile); - final Path pathToVertex = assetFolder.relativize(vertexFile); - - final VarTable vars = getVars(); - final String glslVersion = vars.getString(PROP_GLSL_VERSION); - - final String mdName = filename.length() > 1 ? - toUpperCase(filename.charAt(0)) + filename.substring(1, filename.length()) : filename; - - String mdContent = MD_TEMPLATE.replace("${matdef-name}", mdName); - mdContent = mdContent.replace("${light-mode}", TechniqueDef.LightMode.SinglePass.name()); - mdContent = mdContent.replace("${GLSL-version}", glslVersion); - mdContent = mdContent.replace("${vertex-path}", pathToVertex.toString()); - mdContent = mdContent.replace("${fragment-path}", pathToFragment.toString()); - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(matDefFile, WRITE, TRUNCATE_EXISTING, CREATE))) { - out.print(mdContent); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(fragmentFile, WRITE, TRUNCATE_EXISTING, CREATE))) { - out.print(FRAG_TEMPLATE); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(vertexFile, WRITE, TRUNCATE_EXISTING, CREATE))) { - out.print(VERT_TEMPLATE); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - notifyFileCreated(matDefFile, true); - notifyFileCreated(fragmentFile, false); - notifyFileCreated(vertexFile, false); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/texture/SingleColorTextureFileCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/texture/SingleColorTextureFileCreator.java deleted file mode 100644 index 5f504e95..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/texture/SingleColorTextureFileCreator.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.ss.editor.ui.component.creator.impl.texture; - -import static com.ss.editor.extension.property.EditablePropertyType.COLOR; -import static com.ss.editor.extension.property.EditablePropertyType.INTEGER; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.ColorRGBA; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.plugin.api.file.creator.GenericFileCreator; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.embed.swing.SwingFXUtils; -import javafx.scene.image.ImageView; -import javafx.scene.image.PixelWriter; -import javafx.scene.image.WritableImage; -import javafx.scene.layout.BorderPane; -import javafx.scene.paint.Color; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The creator to create a texture which filled one color. - * - * @author JavaSaBr - */ -public class SingleColorTextureFileCreator extends GenericFileCreator { - - @NotNull - private static final String PROP_COLOR = "color"; - - @NotNull - private static final String PROP_HEIGHT = "height"; - - @NotNull - private static final String PROP_WIDTH = "width"; - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - @NotNull - private static final Array DEFINITIONS = ArrayFactory.newArray(PropertyDefinition.class); - - static { - DESCRIPTION.setFileDescription(Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(SingleColorTextureFileCreator::new); - DEFINITIONS.add(new PropertyDefinition(COLOR, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_COLOR, PROP_COLOR, ColorRGBA.Gray)); - DEFINITIONS.add(new PropertyDefinition(INTEGER, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_HEIGHT, PROP_HEIGHT, 2, 1, 256)); - DEFINITIONS.add(new PropertyDefinition(INTEGER, Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_WIDTH, PROP_WIDTH, 2, 1, 256)); - } - - /** - * The image view to show preview of texture. - */ - @Nullable - private ImageView imageView; - - @Override - @FxThread - protected void createPreview(@NotNull final BorderPane container) { - super.createPreview(container); - imageView = new ImageView(); - container.setCenter(imageView); - } - - /** - * @return the image view to show preview of texture. - */ - @FxThread - private @NotNull ImageView getImageView() { - return notNull(imageView); - } - - @Override - @FromAnyThread - protected boolean needPreview() { - return true; - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.SINGLE_COLOR_TEXTURE_FILE_CREATOR_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return FileExtensions.IMAGE_PNG; - } - - @Override - @FromAnyThread - protected @NotNull Array getPropertyDefinitions() { - return DEFINITIONS; - } - - @Override - @FxThread - protected boolean validate(@NotNull final VarTable vars) { - - final Color color = UiUtils.from(vars.get(PROP_COLOR, ColorRGBA.class)); - - final int width = vars.getInteger(PROP_WIDTH); - final int height = vars.getInteger(PROP_HEIGHT); - - final WritableImage writableImage = new WritableImage(width, height); - final PixelWriter pixelWriter = writableImage.getPixelWriter(); - - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - pixelWriter.setColor(i, j, color); - } - } - - getImageView().setImage(writableImage); - return true; - } - - @Override - @BackgroundThread - protected void writeData(@NotNull final VarTable vars, final @NotNull Path resultFile) throws IOException { - super.writeData(vars, resultFile); - - final Color color = UiUtils.from(vars.get(PROP_COLOR, ColorRGBA.class)); - - final int width = vars.getInteger(PROP_WIDTH); - final int height = vars.getInteger(PROP_HEIGHT); - - final WritableImage writableImage = new WritableImage(width, height); - final PixelWriter pixelWriter = writableImage.getPixelWriter(); - - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - pixelWriter.setColor(i, j, color); - } - } - - final BufferedImage bufferedImage = SwingFXUtils.fromFXImage(writableImage, null); - - try (final OutputStream out = Files.newOutputStream(resultFile)) { - ImageIO.write(bufferedImage, "png", out); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/EditorDescription.java b/src/main/java/com/ss/editor/ui/component/editor/EditorDescription.java deleted file mode 100644 index dd5593b7..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/EditorDescription.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.ss.editor.ui.component.editor; - -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.Callable; - -/** - * The class to describe an editor. - * - * @author JavaSar - */ -public class EditorDescription { - - /** - * The list of supported extensions. - */ - @NotNull - private final Array extensions; - - /** - * The editor constructor. - */ - private Callable constructor; - - /** - * The editor name. - */ - private String editorName; - - /** - * The editor id. - */ - private String editorId; - - /** - * The icon. - */ - @Nullable - private Image icon; - - /** - * Instantiates a new Editor description. - */ - public EditorDescription() { - this.extensions = ArrayFactory.newArray(String.class); - } - - /** - * Gets editor id. - * - * @return the editor id. - */ - @NotNull - public String getEditorId() { - return editorId; - } - - /** - * Sets editor id. - * - * @param editorId the editor id. - */ - public void setEditorId(@NotNull final String editorId) { - this.editorId = editorId; - } - - /** - * Add extension. - * - * @param extension the supported extension. - */ - public void addExtension(@NotNull final String extension) { - this.extensions.add(extension); - } - - /** - * Sets list of extensions. - * - * @param extensions the list of extensions. - */ - public void setExtensions(@NotNull final Array extensions) { - this.extensions.clear(); - this.extensions.addAll(extensions); - } - - /** - * Gets extensions. - * - * @return the list of supported extensions. - */ - @NotNull - public Array getExtensions() { - return extensions; - } - - /** - * Gets constructor. - * - * @return the editor constructor. - */ - @NotNull - public Callable getConstructor() { - return constructor; - } - - /** - * Sets constructor. - * - * @param constructor the editor constructor. - */ - public void setConstructor(@NotNull final Callable constructor) { - this.constructor = constructor; - } - - /** - * Gets editor name. - * - * @return the editor name. - */ - @NotNull - public String getEditorName() { - return editorName; - } - - /** - * Sets editor name. - * - * @param editorName the editor name. - */ - public void setEditorName(@NotNull final String editorName) { - this.editorName = editorName; - } - - /** - * Gets icon. - * - * @return the icon. - */ - @Nullable - public Image getIcon() { - return icon; - } - - /** - * Sets icon. - * - * @param icon the icon. - */ - public void setIcon(@Nullable final Image icon) { - this.icon = icon; - } - - @Override - public String toString() { - return "EditorDescription{" + - "extensions=" + extensions + - ", constructor=" + constructor + - ", editorName='" + editorName + '\'' + - ", editorId='" + editorId + '\'' + - '}'; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/EditorRegistry.java b/src/main/java/com/ss/editor/ui/component/editor/EditorRegistry.java deleted file mode 100644 index 17364b74..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/EditorRegistry.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.ss.editor.ui.component.editor; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.array.ArrayFactory.newArray; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.editor.impl.*; -import com.ss.editor.ui.component.editor.impl.material.MaterialFileEditor; -import com.ss.editor.ui.component.editor.impl.model.ModelFileEditor; -import com.ss.editor.ui.component.editor.impl.scene.SceneFileEditor; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.Callable; - -/** - * THe registry of editors. - * - * @author JavaSaBr - */ -public class EditorRegistry { - - @NotNull - private static final Logger LOGGER = LoggerManager.getLogger(EditorRegistry.class); - - /** - * The constant ALL_FORMATS. - */ - @NotNull - public static final String ALL_FORMATS = "*"; - - @NotNull - private static final EditorRegistry INSTANCE = new EditorRegistry(); - - /** - * Gets instance. - * - * @return the instance - */ - @NotNull - public static EditorRegistry getInstance() { - return INSTANCE; - } - - /** - * The table with editor descriptions. - */ - @NotNull - private final ObjectDictionary> editorDescriptions; - - /** - * The table with mapping editor id to editor description. - */ - @NotNull - private final ObjectDictionary editorIdToDescription; - - /** - * Instantiates a new Editor registry. - */ - public EditorRegistry() { - this.editorDescriptions = DictionaryFactory.newObjectDictionary(); - this.editorIdToDescription = DictionaryFactory.newObjectDictionary(); - loadDescriptions(); - } - - /** - * Load available descriptors. - */ - private void loadDescriptions() { - register(TextFileEditor.DESCRIPTION); - register(MaterialFileEditor.DESCRIPTION); - register(ModelFileEditor.DESCRIPTION); - register(ImageViewerEditor.DESCRIPTION); - register(GLSLFileEditor.DESCRIPTION); - register(MaterialDefinitionFileEditor.DESCRIPTION); - register(AudioViewerEditor.DESCRIPTION); - register(SceneFileEditor.DESCRIPTION); - } - - /** - * @return the table with editor descriptions. - */ - @NotNull - private ObjectDictionary> getEditorDescriptions() { - return editorDescriptions; - } - - /** - * @return the table with mapping editor id to editor description. - */ - @NotNull - private ObjectDictionary getEditorIdToDescription() { - return editorIdToDescription; - } - - /** - * Add new description. - * - * @param description the description of an editor. - */ - @FromAnyThread - public void register(@NotNull final EditorDescription description) { - - final ObjectDictionary> editorDescriptions = getEditorDescriptions(); - - final Array extensions = description.getExtensions(); - extensions.forEach(extension -> register(description, extension, editorDescriptions)); - - final ObjectDictionary editorIdToDescription = getEditorIdToDescription(); - editorIdToDescription.put(description.getEditorId(), description); - } - - @FromAnyThread - private void register(@NotNull final EditorDescription description, @NotNull final String extension, - @NotNull final ObjectDictionary> editorDescriptions) { - final Array descriptions = editorDescriptions.get(extension, () -> newArray(EditorDescription.class)); - notNull(descriptions); - descriptions.add(description); - } - - /** - * Gets description. - * - * @param editorId the editor id - * @return the description for the editor id or null. - */ - @Nullable - @FromAnyThread - public EditorDescription getDescription(@NotNull final String editorId) { - final ObjectDictionary editorIdToDescription = getEditorIdToDescription(); - return editorIdToDescription.get(editorId); - } - - /** - * Create an editor for the file. - * - * @param file the edited file. - * @return the editor for this file or null. - */ - @Nullable - @FromAnyThread - public FileEditor createEditorFor(@NotNull final Path file) { - if (Files.isDirectory(file)) return null; - - final String extension = FileUtils.getExtension(file); - final ObjectDictionary> editorDescriptions = getEditorDescriptions(); - - Array descriptions = editorDescriptions.get(extension); - EditorDescription description; - - if (descriptions != null) { - description = descriptions.first(); - } else { - descriptions = editorDescriptions.get(ALL_FORMATS); - description = descriptions == null ? null : descriptions.first(); - } - - if (description == null) return null; - - final Callable constructor = description.getConstructor(); - try { - return constructor.call(); - } catch (Exception e) { - LOGGER.warning(e); - } - - return null; - } - - /** - * Create an editor for the file. - * - * @param description the editor description. - * @param file the edited file. - * @return the editor or null. - */ - @Nullable - @FromAnyThread - public FileEditor createEditorFor(@NotNull final EditorDescription description, @NotNull final Path file) { - - final Callable constructor = description.getConstructor(); - - try { - return constructor.call(); - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Gets available editors for. - * - * @param file the file - * @return the list of available editors for the file. - */ - @NotNull - @FromAnyThread - public Array getAvailableEditorsFor(@NotNull final Path file) { - - final Array result = newArray(EditorDescription.class); - final String extension = FileUtils.getExtension(file); - - final ObjectDictionary> editorDescriptions = getEditorDescriptions(); - final Array descriptions = editorDescriptions.get(extension); - - if (descriptions != null) { - result.addAll(descriptions); - } - - final Array universal = editorDescriptions.get(ALL_FORMATS); - - if (universal != null) { - result.addAll(universal); - } - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/FileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/FileEditor.java deleted file mode 100644 index 34a45d47..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/FileEditor.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.ss.editor.ui.component.editor; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.part3d.editor.Editor3DPart; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.beans.property.BooleanProperty; -import javafx.event.Event; -import javafx.scene.Parent; -import javafx.scene.layout.BorderPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Consumer; - -/** - * The interface for implementing file editor. - * - * @author JavaSaBr - */ -public interface FileEditor { - - /** - * The Empty states. - */ - @NotNull Array EMPTY_3D_STATES = ArrayFactory.newArray(Editor3DPart.class); - - /** - * Get the page for showing the editor. - * - * @return the page for showing the editor. - */ - @FxThread - @NotNull Parent getPage(); - - /** - * Gets an area to place 3D scene. - * - * @return the area to place 3D scene. - */ - @FxThread - default @Nullable BorderPane get3DArea() { - return null; - } - - /** - * Gets file name. - * - * @return the file name of the current opened file. - */ - @FxThread - @NotNull String getFileName(); - - /** - * Gets edit file. - * - * @return the editing file. - */ - @FxThread - @NotNull Path getEditFile(); - - /** - * Open the file. - * - * @param file the file. - */ - @FxThread - void openFile(@NotNull final Path file); - - /** - * Dirty property boolean property. - * - * @return the dirty property of this editor. - */ - @FxThread - @NotNull BooleanProperty dirtyProperty(); - - /** - * Is dirty boolean. - * - * @return true if the current file was changed. - */ - @FxThread - boolean isDirty(); - - /** - * Save new changes. - */ - @FxThread - default void save() { - save(null); - } - - /** - * Save new changes. - * - * @param callback the callback. - */ - @FxThread - default void save(@Nullable Consumer<@NotNull FileEditor> callback) { - } - - /** - * Gets states. - * - * @return the 3D part of this editor. - */ - @FxThread - default @NotNull Array get3DStates() { - return EMPTY_3D_STATES; - } - - /** - * Notify that this editor was closed. - */ - @FxThread - default void notifyClosed() { - } - - /** - * Notify about renamed files. - * - * @param prevFile the prev file - * @param newFile the new file - */ - @FxThread - default void notifyRenamed(@NotNull final Path prevFile, @NotNull final Path newFile) { - } - - /** - * Notify about moved file. - * - * @param prevFile the prev file - * @param newFile the new file - */ - @FxThread - default void notifyMoved(@NotNull final Path prevFile, @NotNull final Path newFile) { - } - - /** - * Gets description. - * - * @return the description of this editor. - */ - @FromAnyThread - @NotNull EditorDescription getDescription(); - - /** - * Notify that this editor was showed. - */ - @FxThread - default void notifyShowed() { - } - - /** - * Notify that this editor was hided. - */ - @FxThread - default void notifyHided() { - } - - /** - * Check the coords that it's inside in the editing area of this editor. - * - * @param sceneX the scene x - * @param sceneY the scene y - * @param eventType the event type. - * @return true if the point is inside in the editing area. - */ - @FxThread - default boolean isInside(double sceneX, double sceneY, @NotNull Class eventType) { - return false; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/FileEditorUtils.java b/src/main/java/com/ss/editor/ui/component/editor/FileEditorUtils.java deleted file mode 100644 index aa4017c5..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/FileEditorUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.component.editor; - -import com.jme3.math.Vector3f; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.part3d.editor.impl.AdvancedAbstractEditor3DPart; -import com.ss.editor.ui.component.editor.state.impl.Editor3DEditorState; -import org.jetbrains.annotations.NotNull; - -/** - * The utility class. - * - * @author JavaSaBr - */ -public class FileEditorUtils { - - /** - * The constant EXECUTOR_MANAGER. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - public static void loadCameraState(@NotNull final Editor3DEditorState editorState, - @NotNull final AdvancedAbstractEditor3DPart editor3DState) { - - final Vector3f cameraLocation = editorState.getCameraLocation(); - - final float hRotation = editorState.getCameraHRotation(); - final float vRotation = editorState.getCameraVRotation(); - final float tDistance = editorState.getCameraTDistance(); - final float cameraSpeed = editorState.getCameraSpeed(); - - EXECUTOR_MANAGER.addJmeTask(() -> editor3DState.updateCameraSettings(cameraLocation, hRotation, vRotation, tDistance, cameraSpeed)); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java b/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java deleted file mode 100644 index b09b32c4..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java +++ /dev/null @@ -1,621 +0,0 @@ -package com.ss.editor.ui.component.editor.area; - -import static com.ss.editor.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.JfxApplication; -import com.ss.editor.JmeApplication; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.file.converter.FileConverterRegistry; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.FileIconManager; -import com.ss.editor.manager.WorkspaceManager; -import com.ss.editor.ui.component.ScreenComponent; -import com.ss.editor.ui.component.creator.FileCreatorRegistry; -import com.ss.editor.ui.component.editor.EditorRegistry; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.editor.ui.css.CssIds; -import com.ss.editor.ui.dialog.ConfirmDialog; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.*; -import com.ss.editor.ui.scene.EditorFxScene; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.concurrent.util.ThreadUtils; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.array.ConcurrentArray; -import com.ss.rlib.common.util.dictionary.ConcurrentObjectDictionary; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.DictionaryUtils; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.beans.value.ObservableValue; -import javafx.collections.ListChangeListener; -import javafx.event.Event; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The component for containing editors. - * - * @author JavaSaBr - */ -public class EditorAreaComponent extends TabPane implements ScreenComponent { - - private static final Logger LOGGER = LoggerManager.getLogger(EditorAreaComponent.class); - - private static final String COMPONENT_ID = "EditorAreaComponent"; - private static final String KEY_EDITOR = "editor"; - - private static final FileConverterRegistry FILE_CONVERTER_REGISTRY = FileConverterRegistry.getInstance(); - private static final FileCreatorRegistry CREATOR_REGISTRY = FileCreatorRegistry.getInstance(); - private static final WorkspaceManager WORKSPACE_MANAGER = WorkspaceManager.getInstance(); - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - private static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - private static final EditorRegistry EDITOR_REGISTRY = EditorRegistry.getInstance(); - private static final FileIconManager ICON_MANAGER = FileIconManager.getInstance(); - - /** - * The table of opened editors. - */ - @NotNull - private final ConcurrentObjectDictionary openedEditors; - - /** - * The list of opened files. - */ - @NotNull - private final ConcurrentArray openingFiles; - - /** - * True if need to ignore change events. - */ - private boolean ignoreOpenedFiles; - - public EditorAreaComponent() { - this.openedEditors = DictionaryFactory.newConcurrentAtomicObjectDictionary(); - this.openingFiles = ArrayFactory.newConcurrentStampedLockArray(Path.class); - - setPickOnBounds(true); - setId(CssIds.EDITOR_AREA_COMPONENT); - getTabs().addListener(this::processChangeTabs); - getSelectionModel().selectedItemProperty() - .addListener(this::switchEditor); - - FX_EVENT_MANAGER.addEventHandler(RequestedOpenFileEvent.EVENT_TYPE, - event -> processOpenFile((RequestedOpenFileEvent) event)); - FX_EVENT_MANAGER.addEventHandler(RequestedCreateFileEvent.EVENT_TYPE, - event -> processCreateFile((RequestedCreateFileEvent) event)); - FX_EVENT_MANAGER.addEventHandler(RequestedConvertFileEvent.EVENT_TYPE, - event -> processConvertFile((RequestedConvertFileEvent) event)); - FX_EVENT_MANAGER.addEventHandler(RenamedFileEvent.EVENT_TYPE, - event -> processEvent((RenamedFileEvent) event)); - FX_EVENT_MANAGER.addEventHandler(MovedFileEvent.EVENT_TYPE, - event -> processEvent((MovedFileEvent) event)); - FX_EVENT_MANAGER.addEventHandler(ChangedCurrentAssetFolderEvent.EVENT_TYPE, - event -> processEvent((ChangedCurrentAssetFolderEvent) event)); - } - - @FxThread - private void switchEditor( - @NotNull ObservableValue observable, - @Nullable Tab oldValue, - @Nullable Tab newValue - ) { - - BorderPane current3DArea = null; - BorderPane new3DArea = null; - - Path newCurrentFile = null; - - if (newValue != null) { - - var properties = newValue.getProperties(); - var fileEditor = (FileEditor) properties.get(KEY_EDITOR); - fileEditor.notifyShowed(); - - newCurrentFile = fileEditor.getEditFile(); - new3DArea = fileEditor.get3DArea(); - } - - if (oldValue != null) { - - var properties = oldValue.getProperties(); - var fileEditor = (FileEditor) properties.get(KEY_EDITOR); - fileEditor.notifyHided(); - - current3DArea = fileEditor.get3DArea(); - } - - var scene = (EditorFxScene) getScene(); - var canvas = scene.getCanvas(); - - if (new3DArea != null) { - new3DArea.setCenter(canvas); - } else if (current3DArea != null) { - current3DArea.setCenter(null); - scene.hideCanvas(); - } - - var workspace = notNull(WORKSPACE_MANAGER.getCurrentWorkspace()); - workspace.updateCurrentEditedFile(newCurrentFile); - - EXECUTOR_MANAGER.addJmeTask(() -> processShowEditor(oldValue, newValue)); - } - - /** - * Handle the event of changing a current asset folder. - */ - @FxThread - private void processEvent(@NotNull ChangedCurrentAssetFolderEvent event) { - setIgnoreOpenedFiles(true); - try { - getTabs().clear(); - loadOpenedFiles(); - } finally { - setIgnoreOpenedFiles(false); - } - } - - /** - * Set true if need to ignore change events. - * - * @param ignoreOpenedFiles true if need to ignore change events. - */ - @FromAnyThread - private void setIgnoreOpenedFiles(boolean ignoreOpenedFiles) { - this.ignoreOpenedFiles = ignoreOpenedFiles; - } - - /** - * Return true if need to ignore change events. - * - * @return true if need to ignore change events. - */ - @FromAnyThread - private boolean isIgnoreOpenedFiles() { - return ignoreOpenedFiles; - } - - /** - * Handle the event of renamed file. - */ - @FxThread - private void processEvent(@NotNull RenamedFileEvent event) { - handleMovedFiles(event.getPrevFile(), event.getNewFile()); - } - - /** - * Handle the event of moved file. - */ - @FxThread - private void processEvent(@NotNull final MovedFileEvent event) { - handleMovedFiles(event.getPrevFile(), event.getNewFile()); - } - - /** - * Handle a moved/renamed file. - * - * @param prevFile the prev version of the file. - * @param newFile the new version of the file. - */ - @FxThread - private void handleMovedFiles(@NotNull Path prevFile, @NotNull Path newFile) { - - var openedEditors = getOpenedEditors(); - var stamp = openedEditors.writeLock(); - try { - - var files = openedEditors.keyArray(Path.class); - - for (var file : files) { - - if (!file.startsWith(prevFile)) { - continue; - } - - var tab = openedEditors.get(file); - var properties = tab.getProperties(); - var fileEditor = (FileEditor) properties.get(KEY_EDITOR); - fileEditor.notifyRenamed(prevFile, newFile); - - if (fileEditor.isDirty()) { - tab.setText("*" + fileEditor.getFileName()); - } else { - tab.setText(fileEditor.getFileName()); - } - - var editFile = fileEditor.getEditFile(); - - openedEditors.remove(file); - openedEditors.put(editFile, tab); - - var workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - - if (workspace != null) { - workspace.removeOpenedFile(file); - workspace.addOpenedFile(editFile, fileEditor); - } - } - - } finally { - openedEditors.writeUnlock(stamp); - } - } - - /** - * Handle the request to convert a file. - */ - @FxThread - private void processConvertFile(@NotNull RequestedConvertFileEvent event) { - - var file = event.getFile(); - var description = event.getDescription(); - var converter = FILE_CONVERTER_REGISTRY.newCreator(description, file); - - if (converter != null) { - converter.convert(file); - } - } - - /** - * Get the tale of opened editors. - * - * @return the tale of opened editors. - */ - @FromAnyThread - private @NotNull ConcurrentObjectDictionary getOpenedEditors() { - return openedEditors; - } - - /** - * Get the list of opened files. - * - * @return the list of opened files. - */ - @FromAnyThread - private @NotNull ConcurrentArray getOpeningFiles() { - return openingFiles; - } - - /** - * Handle the request to create a file. - */ - @FxThread - private void processCreateFile(@NotNull RequestedCreateFileEvent event) { - - var file = event.getFile(); - var description = event.getDescription(); - var fileCreator = CREATOR_REGISTRY.newCreator(description, file); - - if (fileCreator != null) { - fileCreator.start(file); - } - } - - /** - * Handle the request to close a file editor. - */ - @FxThread - private void processChangeTabs(@NotNull ListChangeListener.Change change) { - - if (!change.next()) { - return; - } - - var removed = change.getRemoved(); - if (removed == null || removed.isEmpty()) { - return; - } - - removed.forEach(tab -> { - - var properties = tab.getProperties(); - var fileEditor = (FileEditor) properties.get(KEY_EDITOR); - var editFile = fileEditor.getEditFile(); - - DictionaryUtils.runInWriteLock(getOpenedEditors(), editFile, ObjectDictionary::remove); - - fileEditor.notifyClosed(); - - if (isIgnoreOpenedFiles()) { - return; - } - - var workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - if (workspace != null) { - workspace.removeOpenedFile(editFile); - } - }); - } - - /** - * Get the current showed editor. - * - * @return the current editor. - */ - @FxThread - public @Nullable FileEditor getCurrentEditor() { - - var selectedTab = getSelectionModel() - .getSelectedItem(); - - if (selectedTab == null) { - return null; - } - - return (FileEditor) selectedTab.getProperties() - .get(KEY_EDITOR); - } - - /** - * Handle a changed active file editor. - * - * @param prevTab the previous editor. - * @param newTab the new editor. - */ - @JmeThread - private void processShowEditor(@Nullable Tab prevTab, @Nullable Tab newTab) { - - var stateManager = EditorUtil.getStateManager(); - var canvas = EditorUtil.getFxScene().getCanvas(); - var sceneProcessor = JfxApplication.getInstance() - .getSceneProcessor(); - - boolean enabled = false; - - if (prevTab != null) { - - var fileEditor = (FileEditor) prevTab.getProperties() - .get(KEY_EDITOR); - - var states = fileEditor.get3DStates(); - states.forEach(stateManager::detach); - } - - if (newTab != null) { - - var fileEditor = (FileEditor) newTab.getProperties() - .get(KEY_EDITOR); - - var states = fileEditor.get3DStates(); - states.forEach(stateManager::attach); - - enabled = states.size() > 0; - } - - if (sceneProcessor.isEnabled() != enabled) { - var result = enabled; - EXECUTOR_MANAGER.addFxTask(() -> { - ThreadUtils.sleep(100); - canvas.setOpacity(result ? 1D : 0D); - sceneProcessor.setEnabled(result); - }); - } - } - - /** - * Handle the request to open a file. - */ - @FxThread - private void processOpenFile(@NotNull RequestedOpenFileEvent event) { - - var file = event.getFile(); - - var openedEditors = getOpenedEditors(); - var tab = DictionaryUtils.getInReadLock(openedEditors, file, ObjectDictionary::get); - - if (tab != null) { - getSelectionModel().select(tab); - return; - } - - var openingFiles = getOpeningFiles(); - var stamp = openingFiles.writeLock(); - try { - - if (openingFiles.contains(file)) { - return; - } - - openingFiles.add(file); - - UiUtils.incrementLoading(); - - EXECUTOR_MANAGER.addBackgroundTask(() -> processOpenFileImpl(event, file)); - - } finally { - openingFiles.writeUnlock(stamp); - } - } - - @BackgroundThread - private void processOpenFileImpl(@NotNull RequestedOpenFileEvent event, @NotNull Path file) { - - var scene = EditorUtil.getFxScene(); - - FileEditor editor; - try { - - var description = event.getDescription(); - - editor = description == null ? EDITOR_REGISTRY.createEditorFor(file) : - EDITOR_REGISTRY.createEditorFor(description, file); - - } catch (Throwable e) { - EditorUtil.handleException(null, this, new Exception(e)); - EXECUTOR_MANAGER.addFxTask(scene::decrementLoading); - ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); - return; - } - - if (editor == null) { - EXECUTOR_MANAGER.addFxTask(scene::decrementLoading); - ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); - return; - } - - var resultEditor = editor; - - var jmeApplication = JmeApplication.getInstance(); - var stamp = jmeApplication.asyncLock(); - try { - editor.openFile(file); - } catch (Throwable e) { - EditorUtil.handleException(null, this, new Exception(e)); - ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); - - var workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - if (workspace != null) { - workspace.removeOpenedFile(file); - } - - EXECUTOR_MANAGER.addFxTask(() -> { - UiUtils.decrementLoading(); - resultEditor.notifyClosed(); - }); - - return; - - } finally { - jmeApplication.asyncUnlock(stamp); - } - - EXECUTOR_MANAGER.addFxTask(() -> addEditor(resultEditor, event.isNeedShow())); - } - - /** - * Add and open the new file editor. - * - * @param editor the editor - * @param needShow the need show - */ - @FxThread - private void addEditor(@NotNull FileEditor editor, boolean needShow) { - - var editFile = editor.getEditFile(); - - var tab = new Tab(editor.getFileName()); - tab.setGraphic(new ImageView(ICON_MANAGER.getIcon(editFile, DEFAULT_FILE_ICON_SIZE))); - tab.setContent(editor.getPage()); - tab.setOnCloseRequest(event -> handleRequestToCloseEditor(editor, tab, event)); - tab.getProperties().put(KEY_EDITOR, editor); - - editor.dirtyProperty().addListener((observable, oldValue, newValue) -> - tab.setText(newValue == Boolean.TRUE ? "*" + editor.getFileName() : editor.getFileName())); - - getTabs().add(tab); - - if (needShow) { - getSelectionModel().select(tab); - } - - DictionaryUtils.runInWriteLock(getOpenedEditors(), editFile, tab, ObjectDictionary::put); - ArrayUtils.runInWriteLock(getOpeningFiles(), editFile, Array::fastRemove); - - UiUtils.decrementLoading(); - - if (isIgnoreOpenedFiles()) { - return; - } - - var workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - if (workspace != null) { - workspace.addOpenedFile(editFile, editor); - } - } - - @FxThread - private void handleRequestToCloseEditor(@NotNull FileEditor editor, @NotNull Tab tab, @NotNull Event event) { - - if (!editor.isDirty()) { - return; - } - - var question = Messages.EDITOR_AREA_SAVE_FILE_QUESTION - .replace("%file_name%", editor.getFileName()); - - var dialog = new ConfirmDialog(result -> { - - if (result == null) { - return; - } - - if (result) { - editor.save(fileEditor -> getTabs().remove(tab)); - } else { - getTabs().remove(tab); - } - - }, question); - - dialog.show(); - event.consume(); - } - - @Override - @FromAnyThread - public @Nullable String getComponentId() { - return COMPONENT_ID; - } - - @Override - @FxThread - public void notifyFinishBuild() { - setIgnoreOpenedFiles(true); - try { - loadOpenedFiles(); - } finally { - setIgnoreOpenedFiles(false); - } - } - - /** - * Load all opened files. - */ - @FxThread - private void loadOpenedFiles() { - - var workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - if (workspace == null) { - return; - } - - var assetFolder = workspace.getAssetFolder(); - var editFile = workspace.getCurrentEditedFile(); - - var openedFiles = workspace.getOpenedFiles(); - openedFiles.forEach((assetPath, editorId) -> { - - var description = EDITOR_REGISTRY.getDescription(editorId); - if (description == null) { - return; - } - - var file = assetFolder.resolve(assetPath); - if (!Files.exists(file)) { - return; - } - - var event = new RequestedOpenFileEvent(file); - event.setDescription(description); - event.setNeedShow(StringUtils.equals(assetPath, editFile)); - - processOpenFile(event); - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java deleted file mode 100644 index e84f28de..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java +++ /dev/null @@ -1,724 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import com.jme3.math.Vector3f; -import com.ss.editor.JmeApplication; -import com.ss.editor.Messages; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.part3d.editor.Editor3DPart; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.FileEditor; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.FileChangedEvent; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.Utils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.fx.util.FXUtils; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.event.EventHandler; -import javafx.scene.control.Button; -import javafx.scene.control.Tooltip; -import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.time.LocalTime; -import java.util.function.Consumer; - -/** - * The base implementation of an editor. - * - * @param the type parameter - * @author JavaSaBr - */ -public abstract class AbstractFileEditor implements FileEditor { - - /** - * The loggerA. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(FileEditor.class); - - /** - * The executro manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The event manager. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * The array of 3D parts of this editor. - */ - @NotNull - private final Array editor3DParts; - - /** - * The file changes listener. - */ - @NotNull - private final EventHandler fileChangedHandler; - - /** - * The dirty property. - */ - @NotNull - private final BooleanProperty dirtyProperty; - - /** - * The time when this editor was showed. - */ - @NotNull - private volatile LocalTime showedTime; - - /** - * The save callback. - */ - @Nullable - private Consumer<@NotNull FileEditor> saveCallback; - - /** - * The root element of this editor. - */ - @Nullable - private R root; - - /** - * The edited file. - */ - @Nullable - private Path file; - - /** - * Is left button pressed. - */ - private boolean buttonLeftDown; - - /** - * Is right button pressed. - */ - private boolean buttonRightDown; - - /** - * Is middle button pressed. - */ - private boolean buttonMiddleDown; - - /** - * The flag of saving process. - */ - private boolean saving; - - /** - * Instantiates a new Abstract file editor. - */ - protected AbstractFileEditor() { - this.showedTime = LocalTime.now(); - this.editor3DParts = ArrayFactory.newArray(Editor3DPart.class); - this.dirtyProperty = new SimpleBooleanProperty(this, "dirty", false); - this.fileChangedHandler = this::processChangedFile; - createContent(); - } - - /** - * Add the new 3D part of this editor. - * - * @param editor3DPart the editor app state - */ - @FxThread - protected void addEditor3DPart(@NotNull final Editor3DPart editor3DPart) { - this.editor3DParts.add(editor3DPart); - } - - /** - * Sets edit file. - * - * @param file the edit file. - */ - @FxThread - protected void setEditFile(@NotNull final Path file) { - this.file = file; - } - - /** - * Create content of this editor. - */ - @FxThread - protected void createContent() { - - final VBox container = new VBox(); - final StackPane page = new StackPane(container); - page.setPickOnBounds(true); - - HBox toolbar = null; - - if (needToolbar()) { - - toolbar = new HBox(); - toolbar.prefWidthProperty().bind(container.widthProperty()); - - createToolbar(toolbar); - - FXUtils.addClassTo(toolbar, CssClasses.FILE_EDITOR_TOOLBAR); - FXUtils.addToPane(toolbar, container); - } - - root = createRoot(); - - if (needListenEventsFromPage()) { - root.setOnKeyPressed(this::processKeyPressed); - root.setOnKeyReleased(this::processKeyReleased); - root.setOnMouseReleased(this::processMouseReleased); - root.setOnMousePressed(this::processMousePressed); - } - - createContent(root); - - FXUtils.addToPane(root, container); - - if (toolbar != null) { - root.prefHeightProperty().bind(container.heightProperty().subtract(toolbar.heightProperty())); - } else { - root.prefHeightProperty().bind(container.heightProperty()); - } - - root.prefWidthProperty().bind(container.widthProperty()); - } - - /** - * @return true if need to listen to events from root page of this editor. - */ - protected boolean needListenEventsFromPage() { - return true; - } - - /** - * Handle the mouse released event. - */ - @FxThread - private void processMouseReleased(@NotNull final MouseEvent mouseEvent) { - setButtonLeftDown(mouseEvent.isPrimaryButtonDown()); - setButtonMiddleDown(mouseEvent.isMiddleButtonDown()); - setButtonRightDown(mouseEvent.isSecondaryButtonDown()); - } - - /** - * Handle the mouse pressed event. - */ - @FxThread - private void processMousePressed(@NotNull final MouseEvent mouseEvent) { - setButtonLeftDown(mouseEvent.isPrimaryButtonDown()); - setButtonMiddleDown(mouseEvent.isMiddleButtonDown()); - setButtonRightDown(mouseEvent.isSecondaryButtonDown()); - } - - /** - * Handle the key released event. - * - * @param event the event - */ - @FxThread - protected void processKeyReleased(@NotNull final KeyEvent event) { - - final KeyCode code = event.getCode(); - - if (handleKeyActionImpl(code, false, event.isControlDown(), event.isShiftDown(), false)) { - event.consume(); - } - } - - /** - * Handle a key code. - * - * @param keyCode the key code. - * @param isPressed true if key is pressed. - * @param isControlDown true if control is down. - * @param isShiftDown true if shift is down. - * @param isButtonMiddleDown true if mouse middle button is pressed. - */ - @FromAnyThread - public void handleKeyAction(@NotNull final KeyCode keyCode, final boolean isPressed, final boolean isControlDown, - final boolean isShiftDown, final boolean isButtonMiddleDown) { - EXECUTOR_MANAGER.addFxTask(() -> handleKeyActionImpl(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown)); - } - - /** - * Handle a key code. - * - * @param keyCode the key code. - * @param isPressed true if key is pressed. - * @param isControlDown true if control is down. - * @param isShiftDown true if shift is down. - * @param isButtonMiddleDown true if mouse middle button is pressed. - * @return true if need to consume an event. - */ - @FxThread - protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final boolean isPressed, - final boolean isControlDown, final boolean isShiftDown, - final boolean isButtonMiddleDown) { - return false; - } - - /** - * Handle the key pressed event. - * - * @param event the event - */ - @FxThread - protected void processKeyPressed(@NotNull final KeyEvent event) { - - final KeyCode code = event.getCode(); - - if (code == KeyCode.S && event.isControlDown() && isDirty()) { - save(); - } else if (handleKeyActionImpl(code, true, event.isControlDown(), event.isShiftDown(), false)) { - event.consume(); - } - } - - /** - * Create toolbar. - * - * @param container the container - */ - @FxThread - protected void createToolbar(@NotNull final HBox container) { - } - - /** - * Create the save action. - * - * @return the button - */ - protected @NotNull Button createSaveAction() { - - final Button action = new Button(); - action.setTooltip(new Tooltip(Messages.FILE_EDITOR_ACTION_SAVE + " (Ctrl + S)")); - action.setOnAction(event -> save()); - action.setGraphic(new ImageView(Icons.SAVE_16)); - action.disableProperty().bind(dirtyProperty().not()); - - FXUtils.addClassesTo(action, CssClasses.FLAT_BUTTON, - CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); - - DynamicIconSupport.addSupport(action); - - return action; - } - - @Override - @FxThread - public void save(@Nullable final Consumer<@NotNull FileEditor> callback) { - if(isSaving()) return; - - this.saveCallback = callback; - notifyStartSaving(); - - EXECUTOR_MANAGER.addBackgroundTask(() -> { - - final EditorDescription description = getDescription(); - final String editorId = description.getEditorId(); - - final Path tempFile = Utils.get(editorId, prefix -> Files.createTempFile(prefix, "toSave.tmp")); - final JmeApplication jmeApplication = JmeApplication.getInstance(); - final long stamp = jmeApplication.asyncLock(); - try { - - final Path editFile = getEditFile(); - - doSave(tempFile); - try (final OutputStream out = Files.newOutputStream(editFile, TRUNCATE_EXISTING)) { - Files.copy(tempFile, out); - } finally { - FileUtils.delete(tempFile); - } - - } catch (final IOException e) { - LOGGER.warning(this, e); - EXECUTOR_MANAGER.addFxTask(this::notifyFinishSaving); - } finally { - jmeApplication.asyncUnlock(stamp); - } - - EXECUTOR_MANAGER.addFxTask(this::postSave); - }); - } - - /** - * Save new changes. - * - * @param toStore the file to store. - * @throws IOException if was some problem with writing to the to store file. - */ - @BackgroundThread - protected void doSave(@NotNull final Path toStore) throws IOException { - } - - /** - * Do some actions after saving. - */ - @FxThread - protected void postSave() { - setDirty(false); - } - - /** - * Need toolbar boolean. - * - * @return true if this editor needs a toolbar. - */ - @FxThread - protected boolean needToolbar() { - return false; - } - - /** - * Create root r. - * - * @return the new root. - */ - @FxThread - protected abstract @NotNull R createRoot(); - - /** - * Create content. - * - * @param root the root - */ - @FxThread - protected abstract void createContent(@NotNull final R root); - - @Override - @FxThread - public @NotNull Pane getPage() { - final R pane = notNull(root); - return (Pane) pane.getParent().getParent(); - } - - @Override - @FxThread - public @NotNull Path getEditFile() { - return notNull(file); - } - - @Override - @FxThread - public @NotNull String getFileName() { - final Path editFile = getEditFile(); - final Path fileName = editFile.getFileName(); - return fileName.toString(); - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - FX_EVENT_MANAGER.addEventHandler(FileChangedEvent.EVENT_TYPE, getFileChangedHandler()); - - this.file = file; - this.showedTime = LocalTime.now(); - - final EditorDescription description = getDescription(); - - GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_OPENED, - description.getEditorId() + "/" + getFileName()); - - GAnalytics.sendPageView(description.getEditorId(), null, "/editing/" + description.getEditorId()); - } - - @Override - @FxThread - public @NotNull BooleanProperty dirtyProperty() { - return dirtyProperty; - } - - @Override - @FxThread - public boolean isDirty() { - return dirtyProperty.get(); - } - - /** - * Set the flag of dirty of this editor. - * - * @param dirty the dirty - */ - @FxThread - protected void setDirty(final boolean dirty) { - this.dirtyProperty.setValue(dirty); - } - - @Override - @FxThread - public @NotNull Array get3DStates() { - return editor3DParts; - } - - @Override - @FxThread - public void notifyRenamed(@NotNull final Path prevFile, @NotNull final Path newFile) { - notifyChangedEditedFile(prevFile, newFile); - } - - @Override - @FxThread - public void notifyMoved(@NotNull final Path prevFile, final @NotNull Path newFile) { - notifyChangedEditedFile(prevFile, newFile); - } - - /** - * Notify about changed the edited file. - * - * @param prevFile the prev file. - * @param newFile the new file. - */ - @FxThread - private void notifyChangedEditedFile(final @NotNull Path prevFile, final @NotNull Path newFile) { - - final Path editFile = getEditFile(); - - if (editFile.equals(prevFile)) { - setEditFile(newFile); - return; - } - - if (!editFile.startsWith(prevFile)) return; - - final Path relativeFile = editFile.subpath(prevFile.getNameCount(), editFile.getNameCount()); - final Path resultFile = newFile.resolve(relativeFile); - - setEditFile(resultFile); - } - - /** - * Notify about changed editor camera settings. - * - * @param cameraLocation the camera location. - * @param hRotation the h rotation. - * @param vRotation the v rotation. - * @param targetDistance the target distance. - * @param cameraSpeed the camera speed. - */ - @FxThread - public void notifyChangedCameraSettings(@NotNull final Vector3f cameraLocation, final float hRotation, - final float vRotation, final float targetDistance, - final float cameraSpeed) { - } - - @Override - @FxThread - public void notifyShowed() { - this.showedTime = LocalTime.now(); - - final EditorDescription description = getDescription(); - GAnalytics.sendPageView(description.getEditorId(), null, "/editing/" + description.getEditorId()); - } - - @Override - @FxThread - public void notifyHided() { - - final Duration duration = Duration.between(showedTime, LocalTime.now()); - final int seconds = (int) duration.getSeconds(); - - final EditorDescription description = getDescription(); - - GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, - seconds, description.getEditorId()); - } - - @Override - @FxThread - public void notifyClosed() { - FX_EVENT_MANAGER.removeEventHandler(FileChangedEvent.EVENT_TYPE, getFileChangedHandler()); - - final Duration duration = Duration.between(showedTime, LocalTime.now()); - final int seconds = (int) duration.getSeconds(); - - final EditorDescription description = getDescription(); - - GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EDITOR_CLOSED, - description.getEditorId() + "/" + getFileName()); - - GAnalytics.sendTiming(GAEvent.Category.EDITOR, GAEvent.Label.WORKING_ON_AN_EDITOR, - seconds, description.getEditorId()); - } - - /** - * Handle a changed file. - * - * @param event the event - */ - @FxThread - protected void processChangedFile(@NotNull final FileChangedEvent event) { - - final Path file = event.getFile(); - final Path editFile = getEditFile(); - - if (!file.equals(editFile)) { - return; - } - - if (isSaving()) { - notifyFinishSaving(); - return; - } - - handleExternalChanges(); - } - - /** - * Handle external changes of the edited file. - */ - @FxThread - protected void handleExternalChanges() { - - } - - /** - * @return the file changes listener. - */ - @FxThread - private @NotNull EventHandler getFileChangedHandler() { - return fileChangedHandler; - } - - @Override - public String toString() { - return "AbstractFileEditor{" + - "dirtyProperty=" + dirtyProperty.get() + - ", file=" + file + - '}'; - } - - /** - * Sets button left down. - * - * @param buttonLeftDown the left button is pressed. - */ - @FxThread - protected void setButtonLeftDown(final boolean buttonLeftDown) { - this.buttonLeftDown = buttonLeftDown; - } - - /** - * Sets button middle down. - * - * @param buttonMiddleDown the middle button is pressed. - */ - @FxThread - protected void setButtonMiddleDown(final boolean buttonMiddleDown) { - this.buttonMiddleDown = buttonMiddleDown; - } - - /** - * Sets button right down. - * - * @param buttonRightDown the right button is pressed. - */ - @FxThread - protected void setButtonRightDown(final boolean buttonRightDown) { - this.buttonRightDown = buttonRightDown; - } - - /** - * Is button left down boolean. - * - * @return true if left button is pressed. - */ - @FxThread - protected boolean isButtonLeftDown() { - return buttonLeftDown; - } - - /** - * Is button middle down boolean. - * - * @return true if middle button is pressed. - */ - @FxThread - protected boolean isButtonMiddleDown() { - return buttonMiddleDown; - } - - /** - * Is button right down boolean. - * - * @return true if right button is pressed. - */ - @FxThread - protected boolean isButtonRightDown() { - return buttonRightDown; - } - - /** - * Is saving boolean. - * - * @return the boolean - */ - @FxThread - protected boolean isSaving() { - return saving; - } - - /** - * Sets saving. - * - * @param saving the saving - */ - @FxThread - protected void setSaving(final boolean saving) { - this.saving = saving; - } - - /** - * Notify start saving. - */ - @FxThread - protected void notifyStartSaving() { - UiUtils.incrementLoading(); - setSaving(true); - } - - /** - * Notify finish saving. - */ - @FxThread - protected void notifyFinishSaving() { - setSaving(false); - UiUtils.decrementLoading(); - if (saveCallback != null) { - saveCallback.accept(this); - saveCallback = null; - } - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/AudioViewerEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/AudioViewerEditor.java deleted file mode 100644 index a40961da..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/AudioViewerEditor.java +++ /dev/null @@ -1,331 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import static com.jme3.audio.AudioSource.Status.Playing; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioSource; -import com.ss.editor.JmeApplication; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.part3d.editor.impl.audio.AudioViewer3DPart; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.image.ImageView; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The implementation of the {@link JmeApplication} to view audio files. - * - * @author JavaSaBr - */ -public class AudioViewerEditor extends AbstractFileEditor { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setConstructor(AudioViewerEditor::new); - DESCRIPTION.setEditorName(Messages.AUDIO_VIEWER_EDITOR_NAME); - DESCRIPTION.setEditorId(AudioViewerEditor.class.getSimpleName()); - DESCRIPTION.setExtensions(FileExtensions.AUDIO_EXTENSIONS); - } - - /** - * The editor app state. - */ - @NotNull - private final AudioViewer3DPart editorAppState; - - /** - * The play button. - */ - @Nullable - private Button playButton; - - /** - * The stop button. - */ - @Nullable - private Button stopButton; - - /** - * The duration field. - */ - @Nullable - private TextField durationField; - - /** - * The bits per sample field. - */ - @Nullable - private TextField bitsPerSampleField; - - /** - * The channels field. - */ - @Nullable - private TextField channelsField; - - /** - * The data type field. - */ - @Nullable - private TextField dataTypeField; - - /** - * The sample rate field. - */ - @Nullable - private TextField sampleRateField; - - private AudioViewerEditor() { - this.editorAppState = new AudioViewer3DPart(this); - addEditor3DPart(editorAppState); - } - - @Override - @FxThread - protected @NotNull VBox createRoot() { - return new VBox(); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - - final Label durationLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_DURATION_LABEL + ":"); - final Label bitsPerSampleLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_BITS_PER_SAMPLE_LABEL + ":"); - final Label channelsLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_CHANNELS_LABEL + ":"); - final Label dataTypeLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_DATA_TYPE_LABEL + ":"); - final Label sampleRateLabel = new Label(Messages.AUDIO_VIEWER_EDITOR_SAMPLE_RATE_LABEL + ":"); - - durationField = new TextField(); - durationField.setEditable(false); - - bitsPerSampleField = new TextField(); - bitsPerSampleField.setEditable(false); - - channelsField = new TextField(); - channelsField.setEditable(false); - - dataTypeField = new TextField(); - dataTypeField.setEditable(false); - - sampleRateField = new TextField(); - sampleRateField.setEditable(false); - - final GridPane gridPane = new GridPane(); - gridPane.add(durationLabel, 0, 0); - gridPane.add(bitsPerSampleLabel, 0, 1); - gridPane.add(channelsLabel, 0, 2); - gridPane.add(dataTypeLabel, 0, 3); - gridPane.add(sampleRateLabel, 0, 4); - gridPane.add(durationField, 1, 0); - gridPane.add(bitsPerSampleField, 1, 1); - gridPane.add(channelsField, 1, 2); - gridPane.add(dataTypeField, 1, 3); - gridPane.add(sampleRateField, 1, 4); - - playButton = new Button(); - playButton.setGraphic(new ImageView(Icons.PLAY_128)); - playButton.setOnAction(event -> processPlay()); - - stopButton = new Button(); - stopButton.setGraphic(new ImageView(Icons.STOP_128)); - stopButton.setOnAction(event -> processStop()); - stopButton.setDisable(true); - - final HBox container = new HBox(); - - FXUtils.addToPane(gridPane, container); - FXUtils.addToPane(playButton, container); - FXUtils.addToPane(stopButton, container); - FXUtils.addToPane(container, root); - - FXUtils.addClassTo(playButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER); - FXUtils.addClassTo(stopButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER); - FXUtils.addClassTo(container, CssClasses.DEF_HBOX); - FXUtils.addClassTo(gridPane, CssClasses.DEF_GRID_PANE); - FXUtils.addClassesTo(root, CssClasses.DEF_VBOX, CssClasses.AUDIO_VIEW_EDITOR_CONTAINER); - - DynamicIconSupport.addSupport(playButton, stopButton); - } - - /** - * Stop of plying. - */ - @FxThread - private void processStop() { - getEditorAppState().stop(); - } - - /** - * Play the audio. - */ - @FxThread - private void processPlay() { - final AudioViewer3DPart appState = getEditorAppState(); - if (appState.getPrevStatus() == Playing) { - appState.pause(); - } else { - appState.play(); - } - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - - final Path assetFile = notNull(EditorUtil.getAssetFile(file)); - final String assetPath = EditorUtil.toAssetPath(assetFile); - - final AudioKey audioKey = new AudioKey(assetPath); - final AssetManager assetManager = EditorUtil.getAssetManager(); - final AudioData audioData = assetManager.loadAudio(audioKey); - - final float duration = audioData.getDuration(); - final int bitsPerSample = audioData.getBitsPerSample(); - final int channels = audioData.getChannels(); - final AudioData.DataType dataType = audioData.getDataType(); - final int sampleRate = audioData.getSampleRate(); - - final AudioViewer3DPart editorAppState = getEditorAppState(); - editorAppState.load(audioData, audioKey); - - getChannelsField().setText(String.valueOf(channels)); - getDurationField().setText(String.valueOf(duration)); - getDataTypeField().setText(String.valueOf(dataType)); - getSampleRateField().setText(String.valueOf(sampleRate)); - getBitsPerSampleField().setText(String.valueOf(bitsPerSample)); - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } - - /** - * @return the editor app state. - */ - @FromAnyThread - private @NotNull AudioViewer3DPart getEditorAppState() { - return editorAppState; - } - - /** - * Notify about changing a status of playing audio. - * - * @param status the new status. - */ - @FxThread - public void notifyChangedStatus(final AudioSource.Status status) { - - final Button playButton = getPlayButton(); - final Button stopButton = getStopButton(); - - switch (status) { - case Playing: { - final ImageView graphic = (ImageView) playButton.getGraphic(); - graphic.setImage(Icons.PAUSE_128); - stopButton.setDisable(false); - break; - } - case Paused: { - final ImageView graphic = (ImageView) playButton.getGraphic(); - graphic.setImage(Icons.PLAY_128); - stopButton.setDisable(false); - break; - } - case Stopped: { - final ImageView graphic = (ImageView) playButton.getGraphic(); - graphic.setImage(Icons.PLAY_128); - stopButton.setDisable(true); - } - } - } - - /** - * @return the play button. - */ - @FxThread - private @NotNull Button getPlayButton() { - return notNull(playButton); - } - - /** - * @return the stop button. - */ - @FxThread - private @NotNull Button getStopButton() { - return notNull(stopButton); - } - - /** - * @return the channels field. - */ - @FxThread - private @NotNull TextField getChannelsField() { - return notNull(channelsField); - } - - /** - * @return the duration field. - */ - @FxThread - private @NotNull TextField getDurationField() { - return notNull(durationField); - } - - /** - * @return the data type field. - */ - @FxThread - private @NotNull TextField getDataTypeField() { - return notNull(dataTypeField); - } - - /** - * @return the sample rate field. - */ - @FxThread - private @NotNull TextField getSampleRateField() { - return notNull(sampleRateField); - } - - /** - * @return the bits per sample field. - */ - @FxThread - private @NotNull TextField getBitsPerSampleField() { - return notNull(bitsPerSampleField); - } - - @Override - public String toString() { - return "AudioViewerEditor{" + - "editorAppState=" + editorAppState + - "} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/CodeAreaFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/CodeAreaFileEditor.java deleted file mode 100644 index a53b0ae3..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/CodeAreaFileEditor.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.code.BaseCodeArea; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.FileUtils; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.fxmisc.richtext.CodeArea; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The implementation of editor to edit files with code. - * - * @author JavaSaBr - */ -public abstract class CodeAreaFileEditor extends AbstractFileEditor { - - /** - * The original content of the opened file. - */ - @Nullable - private String originalContent; - - /** - * The code area. - */ - @Nullable - private BaseCodeArea codeArea; - - @Override - @FxThread - protected @NotNull VBox createRoot() { - return new VBox(); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - - codeArea = createCodeArea(); - codeArea.textProperty().addListener((observable, oldValue, newValue) -> updateDirty(newValue)); - codeArea.prefHeightProperty().bind(root.heightProperty()); - codeArea.prefWidthProperty().bind(root.widthProperty()); - - FXUtils.addToPane(codeArea, root); - FXUtils.addClassTo(codeArea, CssClasses.TEXT_EDITOR_TEXT_AREA); - } - - /** - * Create the code area. - * - * @return the code area. - */ - @FxThread - protected @NotNull BaseCodeArea createCodeArea() { - throw new RuntimeException(); - } - - /** - * Update dirty state. - */ - @FxThread - private void updateDirty(final String newContent) { - setDirty(!getOriginalContent().equals(newContent)); - } - - @Override - @FxThread - protected boolean needToolbar() { - return true; - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - FXUtils.addToPane(createSaveAction(), container); - } - - /** - * @return the code area. - */ - @FxThread - private @NotNull BaseCodeArea getCodeArea() { - return notNull(codeArea); - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - - setOriginalContent(FileUtils.read(file)); - - final BaseCodeArea codeArea = getCodeArea(); - codeArea.loadContent(getOriginalContent()); - - setOriginalContent(codeArea.getText()); - updateDirty(getOriginalContent()); - } - - /** - * @return the original content of the opened file. - */ - @FxThread - private @NotNull String getOriginalContent() { - return notNull(originalContent); - } - - /** - * @param originalContent the original content of the opened file. - */ - @FxThread - private void setOriginalContent(@NotNull final String originalContent) { - this.originalContent = originalContent; - } - - @Override - @BackgroundThread - public void doSave(@NotNull final Path toStore) throws IOException { - super.doSave(toStore); - - final CodeArea codeArea = getCodeArea(); - final String newContent = codeArea.getText(); - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(toStore))) { - out.print(newContent); - } - } - - @Override - @FxThread - protected void postSave() { - super.postSave(); - - final CodeArea codeArea = getCodeArea(); - final String newContent = codeArea.getText(); - - setOriginalContent(newContent); - updateDirty(newContent); - } - - @Override - @FxThread - protected void handleExternalChanges() { - super.handleExternalChanges(); - - final String newContent = FileUtils.read(getEditFile()); - - final BaseCodeArea codeArea = getCodeArea(); - final String currentContent = codeArea.getText(); - codeArea.reloadContent(newContent); - - setOriginalContent(currentContent); - updateDirty(newContent); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/GLSLFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/GLSLFileEditor.java deleted file mode 100644 index 202253a4..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/GLSLFileEditor.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.control.code.BaseCodeArea; -import com.ss.editor.ui.control.code.GLSLCodeArea; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of editor to edit GLSL files. - * - * @author JavaSaBr - */ -public class GLSLFileEditor extends CodeAreaFileEditor { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setConstructor(GLSLFileEditor::new); - DESCRIPTION.setEditorName(Messages.GLSL_FILE_EDITOR_NAME); - DESCRIPTION.setEditorId(GLSLFileEditor.class.getSimpleName()); - DESCRIPTION.setExtensions(FileExtensions.SHADER_EXTENSIONS); - } - - @Override - @FxThread - protected @NotNull BaseCodeArea createCodeArea() { - return new GLSLCodeArea(); - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/ImageViewerEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/ImageViewerEditor.java deleted file mode 100644 index 45e84c1b..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/ImageViewerEditor.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.JmeApplication; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.JavaFxImageManager; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.impl.FileChangedEvent; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The implementation of the {@link JmeApplication} to view image files. - * - * @author JavaSaBr - */ -public class ImageViewerEditor extends AbstractFileEditor { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - @NotNull - private static final JavaFxImageManager JAVA_FX_IMAGE_MANAGER = JavaFxImageManager.getInstance(); - - private static final int IMAGE_SIZE = 512; - - static { - DESCRIPTION.setConstructor(ImageViewerEditor::new); - DESCRIPTION.setEditorName(Messages.IMAGE_VIEWER_EDITOR_NAME); - DESCRIPTION.setEditorId(ImageViewerEditor.class.getSimpleName()); - DESCRIPTION.setExtensions(FileExtensions.IMAGE_EXTENSIONS); - } - - /** - * The image view. - */ - @Nullable - private ImageView imageView; - - @Override - @FxThread - protected @NotNull VBox createRoot() { - return new VBox(); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - - imageView = new ImageView(); - - FXUtils.addToPane(imageView, root); - FXUtils.addClassTo(root, CssClasses.IMAGE_VIEW_EDITOR_CONTAINER); - } - - /** - * @return the image view. - */ - @FxThread - private @NotNull ImageView getImageView() { - return notNull(imageView); - } - - @Override - @FxThread - protected void processChangedFile(@NotNull final FileChangedEvent event) { - final Path file = event.getFile(); - if (!getEditFile().equals(file)) return; - EXECUTOR_MANAGER.schedule(() -> EXECUTOR_MANAGER.addFxTask(() -> showImage(file)), 1000); - } - - @FxThread - private void showImage(@NotNull final Path file) { - final Image preview = JAVA_FX_IMAGE_MANAGER.getImagePreview(file, IMAGE_SIZE, IMAGE_SIZE); - final ImageView imageView = getImageView(); - imageView.setImage(preview); - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - showImage(file); - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/MaterialDefinitionFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/MaterialDefinitionFileEditor.java deleted file mode 100644 index afcd301e..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/MaterialDefinitionFileEditor.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.control.code.BaseCodeArea; -import com.ss.editor.ui.control.code.MaterialDefinitionCodeArea; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of editor to edit material definition files. - * - * @author JavaSaBr - */ -public class MaterialDefinitionFileEditor extends CodeAreaFileEditor { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setConstructor(MaterialDefinitionFileEditor::new); - DESCRIPTION.setEditorName(Messages.MATERIAL_DEFINITION_FILE_EDITOR_NAME); - DESCRIPTION.setEditorId(MaterialDefinitionFileEditor.class.getSimpleName()); - DESCRIPTION.addExtension(FileExtensions.JME_MATERIAL_DEFINITION); - } - - @Override - @FxThread - protected @NotNull BaseCodeArea createCodeArea() { - return new MaterialDefinitionCodeArea(); - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/TextFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/TextFileEditor.java deleted file mode 100644 index 555bf520..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/TextFileEditor.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.ss.editor.ui.component.editor.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.EditorRegistry; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.FileUtils; -import javafx.scene.control.TextArea; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The implementation of editor to edit text files. - * - * @author JavaSaBr - */ -public class TextFileEditor extends AbstractFileEditor { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setConstructor(TextFileEditor::new); - DESCRIPTION.setEditorName(Messages.TEXT_FILE_EDITOR_NAME); - DESCRIPTION.setEditorId(TextFileEditor.class.getSimpleName()); - DESCRIPTION.addExtension(EditorRegistry.ALL_FORMATS); - } - - /** - * The original content of the opened file. - */ - @Nullable - private String originalContent; - - /** - * The text area. - */ - @Nullable - private TextArea textArea; - - @Override - @FxThread - protected @NotNull VBox createRoot() { - return new VBox(); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - - textArea = new TextArea(); - textArea.textProperty().addListener((observable, oldValue, newValue) -> updateDirty(newValue)); - textArea.prefHeightProperty().bind(root.heightProperty()); - textArea.prefWidthProperty().bind(root.widthProperty()); - - FXUtils.addToPane(textArea, root); - FXUtils.addClassesTo(textArea, CssClasses.TRANSPARENT_TEXT_AREA); - } - - /** - * Update dirty state. - */ - @FxThread - private void updateDirty(final String newContent) { - setDirty(!getOriginalContent().equals(newContent)); - } - - @Override - @FxThread - protected boolean needToolbar() { - return true; - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - FXUtils.addToPane(createSaveAction(), container); - } - - /** - * @return the text area. - */ - @FxThread - private @NotNull TextArea getTextArea() { - return notNull(textArea); - } - - @Override - @FxThread - public void openFile(@NotNull final Path file) { - super.openFile(file); - - setOriginalContent(FileUtils.read(file)); - - /* TODO added to handle some exceptions - try { - - } catch (final MalformedInputException e) { - throw new RuntimeException("This file isn't a text file.", e); - } */ - - final TextArea textArea = getTextArea(); - textArea.setText(getOriginalContent()); - } - - /** - * @return the original content of the opened file. - */ - @FxThread - private @NotNull String getOriginalContent() { - return notNull(originalContent); - } - - /** - * @param originalContent the original content of the opened file. - */ - @FxThread - private void setOriginalContent(@NotNull final String originalContent) { - this.originalContent = originalContent; - } - - @Override - @BackgroundThread - public void doSave(@NotNull final Path toStore) throws IOException { - super.doSave(toStore); - - final TextArea textArea = getTextArea(); - final String newContent = textArea.getText(); - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(toStore))) { - out.print(newContent); - } - } - - @Override - @FxThread - protected void postSave() { - super.postSave(); - - final TextArea textArea = getTextArea(); - final String newContent = textArea.getText(); - - setOriginalContent(newContent); - updateDirty(newContent); - } - - @Override - @FxThread - protected void handleExternalChanges() { - super.handleExternalChanges(); - - final String newContent = FileUtils.read(getEditFile()); - - final TextArea textArea = getTextArea(); - final String currentContent = textArea.getText(); - textArea.setText(newContent); - - setOriginalContent(currentContent); - updateDirty(newContent); - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java deleted file mode 100644 index 293a9230..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java +++ /dev/null @@ -1,349 +0,0 @@ -package com.ss.editor.ui.component.editor.impl.material; - -import static com.ss.editor.Messages.MATERIAL_EDITOR_NAME; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_FLIPPED_TEXTURES; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_FLIPPED_TEXTURES; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.editor.util.MaterialUtils.updateMaterialIdNeed; -import static com.ss.rlib.common.util.ObjectUtils.notNull; - -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.jme3.asset.MaterialKey; -import com.jme3.asset.TextureKey; -import com.jme3.material.MatParam; -import com.jme3.material.MatParamTexture; -import com.jme3.material.Material; -import com.jme3.material.MaterialDef; -import com.jme3.shader.VarType; -import com.jme3.texture.Texture; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.model.node.material.RootMaterialSettings; -import com.ss.editor.model.undo.EditorOperationControl; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.part3d.editor.impl.material.MaterialEditor3DPart; -import com.ss.editor.plugin.api.editor.material.BaseMaterialEditor3DPart.ModelType; -import com.ss.editor.plugin.api.editor.material.BaseMaterialFileEditor; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.ui.component.editor.state.impl.EditorMaterialEditorState; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.impl.FileChangedEvent; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.MaterialSerializer; -import com.ss.editor.util.MaterialUtils; -import com.ss.rlib.fx.util.FXUtils; -import javafx.collections.ObservableList; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.input.DragEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Supplier; - -/** - * The implementation of the Editor to edit materials. - * - * @author JavaSaBr - */ -public class MaterialFileEditor extends - BaseMaterialFileEditor { - - /** - * The description. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setConstructor(MaterialFileEditor::new); - DESCRIPTION.setEditorName(MATERIAL_EDITOR_NAME); - DESCRIPTION.setEditorId(MaterialFileEditor.class.getSimpleName()); - DESCRIPTION.addExtension(FileExtensions.JME_MATERIAL); - } - - @NotNull - private static final ResourceManager RESOURCE_MANAGER = ResourceManager.getInstance(); - - /** - * The list of material definitions. - */ - @Nullable - private ComboBox materialDefinitionBox; - - /** - * The current editing material. - */ - @Nullable - private Material currentMaterial; - - private MaterialFileEditor() { - super(); - } - - @Override - @FxThread - protected @NotNull MaterialEditor3DPart create3DEditorPart() { - return new MaterialEditor3DPart(this); - } - - @Override - @FxThread - protected void processChangedFile(@NotNull final FileChangedEvent event) { - super.processChangedFile(event); - - final Material currentMaterial = getCurrentMaterial(); - final Path file = event.getFile(); - - EXECUTOR_MANAGER.addJmeTask(() -> { - final Material newMaterial = updateMaterialIdNeed(file, currentMaterial); - if (newMaterial != null) { - EXECUTOR_MANAGER.addFxTask(() -> reload(newMaterial)); - } - }); - } - - @Override - @BackgroundThread - public void doSave(@NotNull final Path toStore) throws IOException { - super.doSave(toStore); - - final Material currentMaterial = getCurrentMaterial(); - final String content = MaterialSerializer.serializeToString(currentMaterial); - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(toStore))) { - out.print(content); - } - } - - @Override - @FxThread - protected void handleExternalChanges() { - super.handleExternalChanges(); - - final Path assetFile = notNull(getAssetFile(getEditFile())); - final MaterialKey materialKey = new MaterialKey(toAssetPath(assetFile)); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material material = assetManager.loadAsset(materialKey); - - reload(material); - - final EditorOperationControl operationControl = getOperationControl(); - operationControl.clear(); - } - - /** - * Try to apply dropped texture. - * - * @param editor the editor. - * @param dragEvent the drag event. - * @param path the path to the texture. - */ - private void applyTexture(@NotNull final MaterialFileEditor editor, @NotNull final DragEvent dragEvent, - @NotNull final Path path) { - - final String textureName = path.getFileName().toString(); - final int textureType = MaterialUtils.getPossibleTextureType(textureName); - - if (textureType == 0) { - return; - } - - final String[] paramNames = MaterialUtils.getPossibleParamNames(textureType); - final Material currentMaterial = getCurrentMaterial(); - final MaterialDef materialDef = currentMaterial.getMaterialDef(); - - final Optional param = Arrays.stream(paramNames) - .map(materialDef::getMaterialParam) - .filter(Objects::nonNull) - .filter(p -> p.getVarType() == VarType.Texture2D) - .findAny(); - - if (!param.isPresent()) { - return; - } - - final MatParam matParam = param.get(); - - EXECUTOR_MANAGER.addJmeTask(() -> { - - final EditorConfig config = EditorConfig.getInstance(); - final Path assetFile = notNull(getAssetFile(path)); - final TextureKey textureKey = new TextureKey(toAssetPath(assetFile)); - textureKey.setFlipY(config.getBoolean(PREF_FLIPPED_TEXTURES, PREF_DEFAULT_FLIPPED_TEXTURES)); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Texture texture = assetManager.loadTexture(textureKey); - texture.setWrap(Texture.WrapMode.Repeat); - - final String paramName = matParam.getName(); - final MatParamTexture textureParam = currentMaterial.getTextureParam(paramName); - final Texture currentTexture = textureParam == null? null : textureParam.getTextureValue(); - - PropertyOperation operation = - new PropertyOperation<>(currentMaterial, paramName, texture, currentTexture); - operation.setApplyHandler((material, newTexture) -> material.setTexture(paramName, newTexture)); - - execute(operation); - }); - } - - @Override - @FxThread - protected void handleDragDroppedEvent(@NotNull final DragEvent dragEvent) { - super.handleDragDroppedEvent(dragEvent); - UiUtils.handleDroppedFile(dragEvent, FileExtensions.TEXTURE_EXTENSIONS, this, - dragEvent, this::applyTexture); - } - - @Override - @FxThread - protected void handleDragOverEvent(@NotNull final DragEvent dragEvent) { - super.handleDragOverEvent(dragEvent); - UiUtils.acceptIfHasFile(dragEvent, FileExtensions.TEXTURE_EXTENSIONS); - } - - - @Override - @FxThread - protected void doOpenFile(@NotNull final Path file) throws IOException { - super.doOpenFile(file); - - final Path assetFile = notNull(getAssetFile(file)); - final MaterialKey materialKey = new MaterialKey(toAssetPath(assetFile)); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material material = assetManager.loadAsset(materialKey); - - final MaterialEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.changeMode(ModelType.BOX); - - reload(material); - } - - @FxThread - @Override - protected @Nullable Supplier getEditorStateFactory() { - return EditorMaterialEditorState::new; - } - - /** - * Reload the material. - */ - @FxThread - private void reload(@NotNull final Material material) { - setCurrentMaterial(material); - setIgnoreListeners(true); - try { - - final MaterialEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.updateMaterial(material); - - getSettingsTree().fill(new RootMaterialSettings(material)); - - final ComboBox materialDefinitionBox = getMaterialDefinitionBox(); - final ObservableList items = materialDefinitionBox.getItems(); - items.clear(); - items.addAll(RESOURCE_MANAGER.getAvailableResources(FileExtensions.JME_MATERIAL_DEFINITION)); - - final MaterialDef materialDef = material.getMaterialDef(); - materialDefinitionBox.getSelectionModel().select(materialDef.getAssetName()); - - } finally { - setIgnoreListeners(false); - } - } - - /** - * @return the list of material definitions. - */ - @FromAnyThread - private @NotNull ComboBox getMaterialDefinitionBox() { - return notNull(materialDefinitionBox); - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - - final Label materialDefinitionLabel = new Label(Messages.MATERIAL_EDITOR_MATERIAL_TYPE_LABEL + ":"); - - materialDefinitionBox = new ComboBox<>(); - materialDefinitionBox.getSelectionModel() - .selectedItemProperty() - .addListener((observable, oldValue, newValue) -> changeType(newValue)); - - FXUtils.addToPane(materialDefinitionLabel, container); - FXUtils.addToPane(materialDefinitionBox, container); - - FXUtils.addClassTo(materialDefinitionLabel, CssClasses.FILE_EDITOR_TOOLBAR_LABEL); - FXUtils.addClassTo(materialDefinitionBox, CssClasses.FILE_EDITOR_TOOLBAR_FIELD); - } - - /** - * Handle changing the type. - */ - @FxThread - private void changeType(@Nullable final String newType) { - if (isIgnoreListeners()) return; - processChangeTypeImpl(newType); - } - - /** - * Handle changing the type. - */ - @FxThread - private void processChangeTypeImpl(@Nullable final String newType) { - if (newType == null) return; - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material newMaterial = new Material(assetManager, newType); - - MaterialUtils.migrateTo(newMaterial, getCurrentMaterial()); - - final EditorOperationControl operationControl = getOperationControl(); - operationControl.clear(); - - incrementChange(); - reload(newMaterial); - } - - @FromAnyThread - private @NotNull Material getCurrentMaterial() { - return notNull(currentMaterial); - } - - /** - * @param currentMaterial the current editing material. - */ - @FxThread - private void setCurrentMaterial(@NotNull final Material currentMaterial) { - this.currentMaterial = currentMaterial; - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java deleted file mode 100644 index 5fcf77ce..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java +++ /dev/null @@ -1,471 +0,0 @@ -package com.ss.editor.ui.component.editor.impl.model; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.asset.TextureKey; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; -import com.jme3.scene.Spatial; -import com.jme3.texture.Texture; -import com.jme3.util.SkyFactory; -import com.jme3.util.SkyFactory.EnvMapType; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.part3d.editor.impl.model.ModelEditor3DPart; -import com.ss.editor.part3d.editor.impl.model.ModelEditorBulletPart; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.impl.AbstractFileEditor; -import com.ss.editor.ui.component.editor.impl.scene.AbstractSceneFileEditor; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.ui.component.editor.state.impl.EditorModelEditorState; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.MaterialUtils; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.*; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.function.Supplier; - -/** - * The implementation of the {@link AbstractFileEditor} for working with {@link Spatial}. - * - * @author JavaSaBr - */ -public class ModelFileEditor extends AbstractSceneFileEditor { - - @NotNull - private static final String NO_FAST_SKY = Messages.MODEL_FILE_EDITOR_NO_SKY; - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setEditorName(Messages.MODEL_FILE_EDITOR_NAME); - DESCRIPTION.setConstructor(ModelFileEditor::new); - DESCRIPTION.setEditorId(ModelFileEditor.class.getSimpleName()); - DESCRIPTION.addExtension(FileExtensions.JME_OBJECT); - } - - @NotNull - private static final Array FAST_SKY_LIST = ArrayFactory.newArray(String.class); - - static { - FAST_SKY_LIST.add(NO_FAST_SKY); - FAST_SKY_LIST.add("graphics/textures/sky/studio.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/env1.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/env2.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/env3.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/env4.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/outside.hdr"); - FAST_SKY_LIST.add("graphics/textures/sky/inside.hdr"); - } - - /** - * The bullet state. - */ - @NotNull - private final ModelEditorBulletPart bulletState; - - /** - * The list of fast skies. - */ - @Nullable - private ComboBox fastSkyComboBox; - - /** - * The light toggle. - */ - @Nullable - private ToggleButton lightButton; - - /** - * The physics toggle. - */ - @Nullable - private ToggleButton physicsButton; - - /** - * The debug physics toggle. - */ - @Nullable - private ToggleButton debugPhysicsButton; - - private ModelFileEditor() { - super(); - this.bulletState = new ModelEditorBulletPart(getEditor3DPart()); - this.bulletState.setEnabled(false); - this.bulletState.setDebugEnabled(false); - this.bulletState.setSpeed(1F); - addEditor3DPart(bulletState); - } - - @Override - @FxThread - protected @NotNull ModelEditor3DPart create3DEditorPart() { - return new ModelEditor3DPart(this); - } - - /** - * Get the list of fast skies. - * - * @return the list of fast skies. - */ - @FxThread - private @NotNull ComboBox getFastSkyComboBox() { - return notNull(fastSkyComboBox); - } - - /** - * Get the light toggle. - * - * @return the light toggle. - */ - @FxThread - private @NotNull ToggleButton getLightButton() { - return notNull(lightButton); - } - - /** - * Get the physics toggle. - * - * @return the physics toggle. - */ - @FxThread - private @NotNull ToggleButton getPhysicsButton() { - return notNull(physicsButton); - } - - /** - * Get the debug physics button. - * - * @return the debug physics button. - */ - @FxThread - private @NotNull ToggleButton getDebugPhysicsButton() { - return notNull(debugPhysicsButton); - } - - @Override - @FxThread - protected void doOpenFile(@NotNull Path file) throws IOException { - super.doOpenFile(file); - - var assetFile = notNull(getAssetFile(file), "Asset file for " + file + " can't be null."); - var modelKey = new ModelKey(toAssetPath(assetFile)); - - var assetManager = EditorUtil.getAssetManager(); - var model = assetManager.loadAsset(modelKey); - - MaterialUtils.cleanUpMaterialParams(model); - - var editor3DPart = getEditor3DPart(); - editor3DPart.openModel(model); - - handleAddedObject(model); - - setCurrentModel(model); - setIgnoreListeners(true); - try { - - getFastSkyComboBox().getSelectionModel() - .select(FAST_SKY_LIST.first()); - - refreshTree(); - - } finally { - setIgnoreListeners(false); - } - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - final EditorModelEditorState editorState = notNull(getEditorState()); - - final ComboBox fastSkyComboBox = getFastSkyComboBox(); - fastSkyComboBox.getSelectionModel().select(editorState.getSkyType()); - - final ToggleButton lightButton = getLightButton(); - lightButton.setSelected(editorState.isEnableLight()); - - final ToggleButton physicsButton = getPhysicsButton(); - physicsButton.setSelected(editorState.isEnablePhysics()); - - final ToggleButton debugPhysicsButton = getDebugPhysicsButton(); - debugPhysicsButton.setSelected(editorState.isEnableDebugPhysics()); - } - - @Override - @FxThread - protected @Nullable Supplier getEditorStateFactory() { - return EditorModelEditorState::new; - } - - @Override - @FxThread - protected void handleAddedObject(@NotNull final Spatial model) { - super.handleAddedObject(model); - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - final Array geometries = ArrayFactory.newArray(Geometry.class); - - NodeUtils.addGeometry(model, geometries); - - if (!geometries.isEmpty()) { - geometries.forEach(geometry -> { - if (geometry.getQueueBucket() == RenderQueue.Bucket.Sky) { - editor3DState.addCustomSky(geometry); - } - }); - } - } - - @Override - @FxThread - protected void handleRemovedObject(@NotNull final Spatial model) { - super.handleRemovedObject(model); - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - final Array geometries = ArrayFactory.newArray(Geometry.class); - - NodeUtils.addGeometry(model, geometries); - - if (!geometries.isEmpty()) { - geometries.forEach(geometry -> { - if (geometry.getQueueBucket() == RenderQueue.Bucket.Sky) { - editor3DState.removeCustomSky(geometry); - } - }); - } - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - - final Label fastSkyLabel = new Label(Messages.MODEL_FILE_EDITOR_FAST_SKY + ":"); - - fastSkyComboBox = new ComboBox<>(); - fastSkyComboBox.getSelectionModel() - .selectedItemProperty() - .addListener((observable, oldValue, newValue) -> changeFastSky(newValue)); - - final ObservableList skyItems = fastSkyComboBox.getItems(); - skyItems.addAll(FAST_SKY_LIST); - - final ResourceManager resourceManager = ResourceManager.getInstance(); - final Array additionalEnvs = resourceManager.getAdditionalEnvs(); - additionalEnvs.forEach(path -> skyItems.add(path.toString())); - - FXUtils.addToPane(fastSkyLabel, container); - FXUtils.addToPane(fastSkyComboBox, container); - } - - @Override - @FxThread - protected void createActions(@NotNull final HBox container) { - super.createActions(container); - - lightButton = new ToggleButton(); - lightButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_CAMERA_LIGHT)); - lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); - lightButton.setSelected(true); - lightButton.selectedProperty() - .addListener((observable, oldValue, newValue) -> changeLight(newValue)); - - physicsButton = new ToggleButton(); - physicsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_PHYSICS)); - physicsButton.setGraphic(new ImageView(Icons.PHYSICS_16)); - physicsButton.setSelected(false); - physicsButton.selectedProperty() - .addListener((observable, oldValue, newValue) -> changePhysics(newValue)); - - debugPhysicsButton = new ToggleButton(); - debugPhysicsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_DEBUG_PHYSICS)); - debugPhysicsButton.setGraphic(new ImageView(Icons.DEBUG_16)); - debugPhysicsButton.setSelected(false); - debugPhysicsButton.selectedProperty() - .addListener((observable, oldValue, newValue) -> changeDebugPhysics(newValue)); - - DynamicIconSupport.addSupport(lightButton, physicsButton, debugPhysicsButton); - - FXUtils.addClassTo(lightButton, physicsButton, debugPhysicsButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); - FXUtils.addToPane(lightButton, physicsButton, debugPhysicsButton, container); - } - - /** - * Handle changing a sky. - */ - @FxThread - private void changeFastSky(@NotNull final String newSky) { - if (isIgnoreListeners()) { - return; - } - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - - if (NO_FAST_SKY.equals(newSky)) { - editor3DState.changeFastSky(null); - final EditorModelEditorState editorState = getEditorState(); - if (editorState != null) editorState.setSkyType(0); - return; - } - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - final TextureKey key = new TextureKey(newSky, true); - key.setGenerateMips(false); - - final Texture texture = assetManager.loadTexture(key); - final Spatial newFastSky = SkyFactory.createSky(assetManager, texture, EnvMapType.EquirectMap); - - editor3DState.changeFastSky(newFastSky); - - final ComboBox fastSkyComboBox = getFastSkyComboBox(); - final SingleSelectionModel selectionModel = fastSkyComboBox.getSelectionModel(); - final int selectedIndex = selectionModel.getSelectedIndex(); - - final EditorModelEditorState editorState = getEditorState(); - if (editorState != null) { - editorState.setSkyType(selectedIndex); - } - } - - /** - * Get the bullet state. - * - * @return the bullet state. - */ - @FxThread - private @NotNull ModelEditorBulletPart getBulletState() { - return bulletState; - } - - /** - * Handle to change enabling of physics. - */ - @FxThread - private void changePhysics(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - EXECUTOR_MANAGER.addJmeTask(() -> getBulletState().setEnabled(newValue)); - - if (editorState != null) { - editorState.setEnablePhysics(newValue); - } - } - - /** - * Handle to change enabling of physics. - */ - @FxThread - private void changeDebugPhysics(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - EXECUTOR_MANAGER.addJmeTask(() -> getBulletState().setDebugEnabled(newValue)); - - if (editorState != null) { - editorState.setEnableDebugPhysics(newValue); - } - } - - /** - * Handle changing camera light visibility. - */ - @FxThread - private void changeLight(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.updateLightEnabled(newValue); - - if (editorState != null) { - editorState.setEnableLight(newValue); - } - } - - @Override - @FxThread - public void notifyFxAddedChild(@NotNull final Object parent, @NotNull final Object added, final int index, - final boolean needSelect) { - super.notifyFxAddedChild(parent, added, index, needSelect); - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - - if (added instanceof Spatial) { - - final Spatial spatial = (Spatial) added; - final boolean isSky = spatial.getQueueBucket() == RenderQueue.Bucket.Sky; - - if (isSky) { - editor3DState.addCustomSky(spatial); - editor3DState.updateLightProbe(); - } - } - - EXECUTOR_MANAGER.addFxTask(() -> getBulletState().notifyAdded(added)); - } - - @Override - @FxThread - public void notifyFxRemovedChild(@NotNull final Object parent, @NotNull final Object removed) { - super.notifyFxRemovedChild(parent, removed); - - final ModelEditor3DPart editor3DState = getEditor3DPart(); - - if (removed instanceof Spatial) { - - final Spatial spatial = (Spatial) removed; - final boolean isSky = spatial.getQueueBucket() == RenderQueue.Bucket.Sky; - - if (isSky) { - editor3DState.removeCustomSky(spatial); - editor3DState.updateLightProbe(); - } - } - - EXECUTOR_MANAGER.addFxTask(() -> getBulletState().notifyRemoved(removed)); - } - - @Override - public String toString() { - return "ModelFileEditor{" + - "} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java deleted file mode 100644 index 03f35805..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java +++ /dev/null @@ -1,1467 +0,0 @@ -package com.ss.editor.ui.component.editor.impl.scene; - -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.editor.util.MaterialUtils.saveIfNeedTextures; -import static com.ss.editor.util.MaterialUtils.updateMaterialIdNeed; -import static com.ss.editor.util.NodeUtils.findParent; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static javafx.collections.FXCollections.observableArrayList; -import com.jme3.asset.AssetManager; -import com.jme3.asset.MaterialKey; -import com.jme3.asset.ModelKey; -import com.jme3.audio.AudioNode; -import com.jme3.bounding.BoundingBox; -import com.jme3.bounding.BoundingSphere; -import com.jme3.bounding.BoundingVolume; -import com.jme3.bullet.control.PhysicsControl; -import com.jme3.export.binary.BinaryExporter; -import com.jme3.light.DirectionalLight; -import com.jme3.light.Light; -import com.jme3.light.PointLight; -import com.jme3.light.SpotLight; -import com.jme3.material.Material; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.jme3.texture.Texture; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.control.transform.EditorTransformSupport.TransformType; -import com.ss.editor.control.transform.EditorTransformSupport.TransformationMode; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.ScenePresentable; -import com.ss.editor.model.editor.ModelEditingProvider; -import com.ss.editor.model.scene.EditorAudioNode; -import com.ss.editor.model.scene.EditorLightNode; -import com.ss.editor.model.scene.EditorPresentableNode; -import com.ss.editor.model.scene.WrapperNode; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.part3d.editor.impl.Stats3DPart; -import com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart; -import com.ss.editor.plugin.api.RenderFilterExtension; -import com.ss.editor.plugin.api.editor.Advanced3DFileEditorWithSplitRightTool; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.scripting.EditorScriptingComponent; -import com.ss.editor.ui.component.editor.state.impl.BaseEditorSceneEditorState; -import com.ss.editor.ui.component.painting.PaintingComponent; -import com.ss.editor.ui.component.painting.PaintingComponentContainer; -import com.ss.editor.ui.component.tab.EditorToolComponent; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.model.ModelPropertyEditor; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.action.impl.multi.RemoveElementsAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.impl.FileChangedEvent; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.*; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.geometry.Point2D; -import javafx.scene.control.*; -import javafx.scene.image.ImageView; -import javafx.scene.input.DragEvent; -import javafx.scene.input.KeyCode; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -/** - * The base implementation of a model file editor. - * - * @param the type edited object. - * @param the type of {@link AbstractSceneEditor3DPart} - * @param the type of an editor state. - * @author JavaSaBr - */ -public abstract class AbstractSceneFileEditor extends - Advanced3DFileEditorWithSplitRightTool implements ModelChangeConsumer, ModelEditingProvider { - - protected static final int OBJECTS_TOOL = 0; - protected static final int PAINTING_TOOL = 1; - protected static final int SCRIPTING_TOOL = 2; - - @NotNull - private static final Array ACCEPTED_FILES = ArrayFactory.asArray( - FileExtensions.JME_MATERIAL, - FileExtensions.JME_OBJECT); - - @NotNull - private static final Array EMPTY_SELECTION = ArrayFactory.newArray(Spatial.class); - - @NotNull - private static final ObservableList TRANSFORMATION_MODES = observableArrayList(TransformationMode.values()); - - /** - * The list of pre-save handlers. - */ - @NotNull - private static final Array> PRE_SAVE_HANDLERS = ArrayFactory.newArray(Consumer.class); - - /** - * The list of post-save handlers. - */ - @NotNull - private static final Array> POST_SAVE_HANDLERS = ArrayFactory.newArray(Consumer.class); - - /** - * Register the new pre-save handler. - * - * @param handler the new pre-save handler. - */ - @FxThread - public static void registerPreSaveHandler(@NotNull Consumer handler) { - PRE_SAVE_HANDLERS.add(handler); - } - - /** - * Register the new post-save handler. - * - * @param handler the new post-save handler. - */ - @FxThread - public static void registerPostSaveHandler(@NotNull Consumer handler) { - PRE_SAVE_HANDLERS.add(handler); - } - - /** - * The stats 3D part. - */ - @NotNull - private final Stats3DPart stats3DPart; - - /** - * The opened model. - */ - @Nullable - private M currentModel; - - /** - * The selection handler. - */ - @Nullable - private Consumer> selectionNodeHandler; - - /** - * The list of transform modes. - */ - @Nullable - private ComboBox transformModeComboBox; - - /** - * The model tree. - */ - @Nullable - private ModelNodeTree modelNodeTree; - - /** - * The model property editor. - */ - @Nullable - private ModelPropertyEditor modelPropertyEditor; - - /** - * The container of painting components. - */ - @Nullable - private PaintingComponentContainer paintingComponentContainer; - - /** - * The scripting component. - */ - @Nullable - private EditorScriptingComponent scriptingComponent; - - /** - * The container of property editor in objects tool. - */ - @Nullable - private VBox propertyEditorObjectsContainer; - - /** - * The container of model node tree in objects tool. - */ - @Nullable - private VBox modelNodeTreeObjectsContainer; - - /** - * The container of model node tree in editing tool. - */ - @Nullable - private VBox modelNodeTreeEditingContainer; - - /** - * The stats container. - */ - @Nullable - private VBox statsContainer; - - /** - * The selection toggle. - */ - @Nullable - private ToggleButton selectionButton; - - /** - * The grid toggle. - */ - @Nullable - private ToggleButton gridButton; - - /** - * The statistics toggle. - */ - @Nullable - private ToggleButton statisticsButton; - - /** - * The move tool toggle. - */ - @Nullable - private ToggleButton moveToolButton; - - /** - * The rotation tool toggle. - */ - @Nullable - private ToggleButton rotationToolButton; - - /** - * The scaling tool toggle. - */ - @Nullable - private ToggleButton scaleToolButton; - - /** - * The flag of ignoring camera moving. - */ - private boolean ignoreCameraMove; - - public AbstractSceneFileEditor() { - this.stats3DPart = new Stats3DPart(notNull(statsContainer)); - addEditor3DPart(stats3DPart); - stats3DPart.setEnabled(true); - processChangeTool(-1, OBJECTS_TOOL); - } - - /** - * Gets model node tree. - * - * @return the model tree. - */ - @FxThread - protected @NotNull ModelNodeTree getModelNodeTree() { - return notNull(modelNodeTree); - } - - /** - * Gets model property editor. - * - * @return the model property editor. - */ - @FxThread - protected @NotNull ModelPropertyEditor getModelPropertyEditor() { - return notNull(modelPropertyEditor); - } - - /** - * Get the container of painting components. - * - * @return the container of painting components. - */ - @FxThread - private @NotNull PaintingComponentContainer getPaintingComponentContainer() { - return notNull(paintingComponentContainer); - } - - /** - * @return the container of property editor in objects tool. - */ - @FxThread - private @NotNull VBox getPropertyEditorObjectsContainer() { - return notNull(propertyEditorObjectsContainer); - } - - /** - * @return the container of model node tree in editing tool. - */ - @FxThread - private @NotNull VBox getModelNodeTreeEditingContainer() { - return notNull(modelNodeTreeEditingContainer); - } - - /** - * @return the container of model node tree in objects tool. - */ - @FxThread - private @NotNull VBox getModelNodeTreeObjectsContainer() { - return notNull(modelNodeTreeObjectsContainer); - } - - /** - * @return the scripting component. - */ - @FxThread - private @NotNull EditorScriptingComponent getScriptingComponent() { - return notNull(scriptingComponent); - } - - @Override - @FxThread - protected void processChangedFile(@NotNull final FileChangedEvent event) { - super.processChangedFile(event); - - final Path file = event.getFile(); - final String extension = FileUtils.getExtension(file); - - if (extension.endsWith(FileExtensions.JME_MATERIAL)) { - EXECUTOR_MANAGER.addJmeTask(() -> updateMaterial(file)); - } else if (MaterialUtils.isShaderFile(file) || MaterialUtils.isTextureFile(file)) { - EXECUTOR_MANAGER.addJmeTask(() -> updateMaterials(file)); - } - } - - /** - * Updating a material from the file. - */ - @FxThread - private void updateMaterial(@NotNull final Path file) { - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - final M currentModel = getCurrentModel(); - - final Array geometries = ArrayFactory.newArray(Geometry.class); - NodeUtils.addGeometryWithMaterial(currentModel, geometries, assetPath); - if (geometries.isEmpty()) return; - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material material = assetManager.loadMaterial(assetPath); - geometries.forEach(geometry -> geometry.setMaterial(material)); - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.refreshFilters(); - } - - /** - * Updating materials. - */ - @FxThread - private void updateMaterials(@NotNull final Path file) { - - final M currentModel = getCurrentModel(); - final AtomicInteger needRefresh = new AtomicInteger(); - - NodeUtils.visitGeometry(currentModel, geometry -> { - - final Material material = geometry.getMaterial(); - final Material newMaterial = updateMaterialIdNeed(file, material); - - if (newMaterial != null) { - geometry.setMaterial(newMaterial); - needRefresh.incrementAndGet(); - } - }); - - if (needRefresh.get() < 1) { - return; - } - - final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); - filterExtension.refreshFilters(); - } - - /** - * Handle a added model. - * - * @param model the model - */ - @FxThread - protected void handleAddedObject(@NotNull final Spatial model) { - - final MA editor3DPart = getEditor3DPart(); - final Array lights = ArrayFactory.newArray(Light.class); - final Array audioNodes = ArrayFactory.newArray(AudioNode.class); - - NodeUtils.addLight(model, lights); - NodeUtils.addAudioNodes(model, audioNodes); - - lights.forEach(editor3DPart, (light, part) -> part.addLight(light)); - audioNodes.forEach(editor3DPart, (audioNode, part) -> part.addAudioNode(audioNode)); - } - - /** - * Handle a removed model.T - * - * @param model the model - */ - @FxThread - protected void handleRemovedObject(@NotNull final Spatial model) { - - final MA editor3DPart = getEditor3DPart(); - final Array lights = ArrayFactory.newArray(Light.class); - final Array audioNodes = ArrayFactory.newArray(AudioNode.class); - - NodeUtils.addLight(model, lights); - NodeUtils.addAudioNodes(model, audioNodes); - - lights.forEach(editor3DPart, (light, part) -> part.removeLight(light)); - audioNodes.forEach(editor3DPart, (audioNode, part) -> part.removeAudioNode(audioNode)); - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - scriptingComponent.addVariable("root", getCurrentModel()); - scriptingComponent.addVariable("assetManager", EditorUtil.getAssetManager()); - scriptingComponent.addImport(Spatial.class); - scriptingComponent.addImport(Geometry.class); - scriptingComponent.addImport(Control.class); - scriptingComponent.addImport(Node.class); - scriptingComponent.addImport(Light.class); - scriptingComponent.addImport(DirectionalLight.class); - scriptingComponent.addImport(PointLight.class); - scriptingComponent.addImport(SpotLight.class); - scriptingComponent.addImport(Material.class); - scriptingComponent.addImport(Texture.class); - scriptingComponent.setExampleCode("root.attachChild(\nnew Node(\"created from Groovy\"));"); - scriptingComponent.buildHeader(); - - final ES editorState = notNull(getEditorState()); - - gridButton.setSelected(editorState.isEnableGrid()); - statisticsButton.setSelected(editorState.isShowStatistics()); - selectionButton.setSelected(editorState.isEnableSelection()); - transformModeComboBox.getSelectionModel() - .select(TransformationMode.valueOf(editorState.getTransformationMode())); - - final Array components = paintingComponentContainer.getComponents(); - components.forEach(editorState, PaintingComponent::loadState); - - final TransformType transformType = TransformType.valueOf(editorState.getTransformationType()); - - switch (transformType) { - case MOVE_TOOL: { - moveToolButton.setSelected(true); - break; - } - case ROTATE_TOOL: { - rotationToolButton.setSelected(true); - break; - } - case SCALE_TOOL: { - scaleToolButton.setSelected(true); - break; - } - default: { - break; - } - } - } - - @Override - @FxThread - protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final boolean isPressed, - final boolean isControlDown, final boolean isShiftDown, - final boolean isButtonMiddleDown) { - - final MA editor3DPart = getEditor3DPart(); - if (editor3DPart.isCameraMoving()) { - return false; - } - - if (isPressed && isControlDown && keyCode == KeyCode.Z) { - undo(); - return true; - } else if (isPressed && isControlDown && keyCode == KeyCode.Y) { - redo(); - return true; - } else if (isPressed && keyCode == KeyCode.G && !isControlDown && !isButtonMiddleDown) { - final ToggleButton moveToolButton = getMoveToolButton(); - moveToolButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.R && !isControlDown && !isButtonMiddleDown) { - final ToggleButton rotationToolButton = getRotationToolButton(); - rotationToolButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.S && !isControlDown && !isButtonMiddleDown) { - final ToggleButton scaleToolButton = getScaleToolButton(); - scaleToolButton.setSelected(true); - return true; - } else if (isPressed && keyCode == KeyCode.DELETE) { - - final RemoveElementsAction removeAction = findTreeAction(RemoveElementsAction.class); - - if (removeAction == null) { - return false; - } - - removeAction.process(); - return true; - - } else if (isPressed && isControlDown && keyCode == KeyCode.C) { - //TODO - } else if (isPressed && isControlDown && keyCode == KeyCode.V) { - //TODO - } - - return super.handleKeyActionImpl(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); - } - - /** - * Find a tree action for the current selected items. - * - * @param type the action's type. - * @param the action's type. - * @return the found action or null. - */ - @FxThread - protected @Nullable T findTreeAction(@NotNull final Class type) { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - final TreeNode selected = modelNodeTree.getSelected(); - if (selected == null || !selected.canRemove()) { - return null; - } - - final ContextMenu contextMenu = modelNodeTree.getContextMenu(null); - return UiUtils.findMenuItem(contextMenu.getItems(), type); - } - - /** - * @return true if need to ignore moving camera. - */ - @FxThread - private boolean isIgnoreCameraMove() { - return ignoreCameraMove; - } - - /** - * @param ignoreCameraMove true if need to ignore moving camera. - */ - @FxThread - private void setIgnoreCameraMove(final boolean ignoreCameraMove) { - this.ignoreCameraMove = ignoreCameraMove; - } - - /** - * Sets current model. - * - * @param currentModel the opened model. - */ - @FxThread - protected void setCurrentModel(@NotNull final M currentModel) { - this.currentModel = currentModel; - } - - @Override - @FxThread - public @NotNull M getCurrentModel() { - return notNull(currentModel); - } - - @Override - @FxThread - public void notifyFxChangeProperty(@Nullable final Object parent, @NotNull final Object object, - @NotNull final String propertyName) { - - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - modelPropertyEditor.syncFor(object); - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.notifyChanged(parent, object); - - if (object instanceof Geometry && Messages.MODEL_PROPERTY_MATERIAL.equals(propertyName)) { - modelNodeTree.refresh(object); - } - - final PaintingComponentContainer editingComponentContainer = getPaintingComponentContainer(); - editingComponentContainer.notifyChangeProperty(object, propertyName); - } - - @Override - public void notifyJmePreChangeProperty(@NotNull final Object object, @NotNull final String propertyName) { - getEditor3DPart().notifyPropertyPreChanged(object, propertyName); - } - - @Override - @FxThread - public void notifyJmeChangedProperty(@NotNull final Object object, @NotNull final String propertyName) { - getEditor3DPart().notifyPropertyChanged(object, propertyName); - } - - @Override - @FxThread - public void notifyFxChangePropertyCount(@NotNull final Object object) { - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - modelPropertyEditor.rebuildFor(object, null); - } - - @Override - @FxThread - public void notifyFxAddedChild(@NotNull final Object parent, @NotNull final Object added, final int index, - final boolean needSelect) { - - final MA editor3DPart = getEditor3DPart(); - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.notifyAdded(parent, added, index); - - if (added instanceof Light) { - editor3DPart.addLight((Light) added); - } else if (added instanceof AudioNode) { - editor3DPart.addAudioNode((AudioNode) added); - } else if (added instanceof Spatial) { - handleAddedObject((Spatial) added); - } - - if (needSelect) { - EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.selectSingle(added))); - } - } - - @Override - @FxThread - public void notifyFxRemovedChild(@NotNull final Object parent, @NotNull final Object removed) { - - final MA editor3DPart = getEditor3DPart(); - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.notifyRemoved(parent, removed); - - if (removed instanceof Light) { - editor3DPart.removeLight((Light) removed); - } else if (removed instanceof AudioNode) { - editor3DPart.removeAudioNode((AudioNode) removed); - } else if (removed instanceof Spatial) { - handleRemovedObject((Spatial) removed); - } - } - - @Override - @FxThread - public void notifyFxReplaced(@NotNull final Object parent, @Nullable final Object oldChild, - @Nullable final Object newChild, final boolean needExpand, - final boolean needDeepExpand) { - - final MA editor3DPart = getEditor3DPart(); - final Spatial currentModel = getCurrentModel(); - - if (currentModel == oldChild && newChild instanceof Spatial) { - handleRemovedObject(currentModel); - editor3DPart.openModel(unsafeCast(newChild)); - handleAddedObject((Spatial) newChild); - setCurrentModel(unsafeCast(newChild)); - } else { - - if (oldChild instanceof Spatial) { - handleRemovedObject((Spatial) oldChild); - } - - if (newChild instanceof Spatial) { - handleAddedObject((Spatial) newChild); - } - } - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.notifyReplace(parent, oldChild, newChild, needExpand, needDeepExpand); - } - - @Override - @FxThread - public void notifyFxMoved(@NotNull final Object prevParent, @NotNull final Object newParent, - @NotNull final Object child, final int index, final boolean needSelect) { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.notifyMoved(prevParent, newParent, child, index); - - if (needSelect) { - EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.selectSingle(child))); - } - } - - /** - * Handle the selected object. - * - * @param object the object - */ - @FxThread - public void notifySelected(@Nullable Object object) { - - if (object instanceof EditorLightNode) { - object = ((EditorLightNode) object).getLight(); - } - - if (object instanceof EditorAudioNode) { - object = ((EditorAudioNode) object).getAudioNode(); - } - - setIgnoreCameraMove(true); - try { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.selectSingle(object); - - final SingleSelectionModel selectionModel = getEditorToolComponent().getSelectionModel(); - if (isNeedToOpenObjectsTool(selectionModel.getSelectedIndex())) { - selectionModel.select(OBJECTS_TOOL); - } - - } finally { - setIgnoreCameraMove(false); - } - } - - /** - * Return true if need to open objects tool. - * - * @param current the current opened tool. - * @return true if need to open objects tool. - */ - @FxThread - protected boolean isNeedToOpenObjectsTool(final int current) { - return !(current == OBJECTS_TOOL || current == SCRIPTING_TOOL); - } - - /** - * Return true of the spatial can be selected. - * - * @param spatial the spatial. - * @return true if the spatial can be selected. - */ - @FxThread - protected boolean canSelect(@NotNull final Spatial spatial) { - return true; - } - - /** - * Handle the selected object from the tree. - * - * @param object the selected object. - */ - @FxThread - public void selectNodeFromTree(@Nullable final Object object) { - - final Array objects = LocalObjects.get().nextObjectArray(); - objects.add(object); - - selectNodesFromTree(objects); - } - - /** - * Handle the selected objects from the tree. - * - * @param objects the selected objects. - */ - @FxThread - public void selectNodesFromTree(@NotNull final Array objects) { - - final MA editor3DPart = getEditor3DPart(); - editor3DPart.select(EMPTY_SELECTION); - - if (objects.size() > 1) { - multiSelectNodesFromTree(objects, editor3DPart); - } else if (objects.size() == 1) { - singleSelectNodesFromTree(objects, editor3DPart); - return; - } else { - editor3DPart.select(EMPTY_SELECTION); - } - - getModelPropertyEditor().buildFor(null, null); - getPaintingComponentContainer().prepareFor(null); - } - - /** - * Handle multi select nodes from tree. - * - * @param objects the selected objects. - * @param editor3DPart the 3D part of this editor. - */ - @FxThread - protected void multiSelectNodesFromTree(@NotNull final Array objects, @NotNull final MA editor3DPart) { - - final Array toSelect = ArrayFactory.newArray(Spatial.class); - - for (final Object object : objects) { - - Object element; - - if (object instanceof TreeNode) { - element = ((TreeNode) object).getElement(); - } else { - element = object; - } - - if (element instanceof SceneLayer) { - element = null; - } - - Spatial spatial = null; - - if (element instanceof AudioNode) { - final EditorAudioNode audioNode = editor3DPart.getAudioNode((AudioNode) element); - spatial = audioNode == null ? null : audioNode.getEditedNode(); - } else if (element instanceof Spatial) { - spatial = (Spatial) element; - } else if (element instanceof Light) { - spatial = editor3DPart.getLightNode((Light) element); - } else if(element instanceof ScenePresentable) { - final EditorPresentableNode presentableNode = editor3DPart.getPresentableNode((ScenePresentable) element); - spatial = presentableNode == null? null : presentableNode.getEditedNode(); - } - - if (spatial != null && !spatial.isVisible()) { - spatial = null; - } - - if(spatial != null && canSelect(spatial)) { - toSelect.add(spatial); - } - } - - editor3DPart.select(toSelect); - } - - /** - * Handle single select nodes from tree. - * - * @param objects the selected objects. - * @param editor3DPart the 3D part of this editor. - */ - @FxThread - protected void singleSelectNodesFromTree(@NotNull final Array objects, @NotNull final MA editor3DPart) { - - Object parent = null; - Object element; - - final Object first = objects.first(); - - if (first instanceof TreeNode) { - final TreeNode treeNode = (TreeNode) first; - final TreeNode parentNode = treeNode.getParent(); - parent = parentNode == null ? null : parentNode.getElement(); - element = treeNode.getElement(); - } else { - element = first; - } - - if (element instanceof SceneLayer) { - element = null; - } - - Spatial spatial = null; - - if (element instanceof AudioNode) { - final EditorAudioNode audioNode = editor3DPart.getAudioNode((AudioNode) element); - spatial = audioNode == null ? null : audioNode.getEditedNode(); - } else if (element instanceof Spatial) { - spatial = (Spatial) element; - parent = spatial.getParent(); - } else if (element instanceof Light) { - spatial = editor3DPart.getLightNode((Light) element); - } else if(element instanceof ScenePresentable) { - final EditorPresentableNode presentableNode = editor3DPart.getPresentableNode((ScenePresentable) element); - spatial = presentableNode == null? null : presentableNode.getEditedNode(); - } - - if (spatial != null && !spatial.isVisible()) { - spatial = null; - } - - if (spatial != null && canSelect(spatial)) { - - editor3DPart.select(spatial); - - if (!isIgnoreCameraMove() && !isVisibleOnEditor(spatial)) { - editor3DPart.cameraLookAt(spatial); - } - } - - getModelPropertyEditor().buildFor(element, parent); - getPaintingComponentContainer().prepareFor(element); - } - - @FxThread - private boolean isVisibleOnEditor(@NotNull final Spatial spatial) { - - final MA editor3DPart = getEditor3DPart(); - final Camera camera = editor3DPart.getCamera(); - - final Vector3f position = spatial.getWorldTranslation(); - final Vector3f coordinates = camera.getScreenCoordinates(position, new Vector3f()); - - boolean invisible = coordinates.getZ() < 0F || coordinates.getZ() > 1F; - invisible = invisible || !isInside(coordinates.getX(), camera.getHeight() - coordinates.getY(), Event.class); - - return !invisible; - } - - @Override - @BackgroundThread - public void doSave(@NotNull final Path toStore) throws IOException { - super.doSave(toStore); - - final M currentModel = getCurrentModel(); - - try { - NodeUtils.visitGeometry(currentModel, geometry -> saveIfNeedTextures(geometry.getMaterial())); - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - PRE_SAVE_HANDLERS.forEach(currentModel, Consumer::accept); - try { - - final BinaryExporter exporter = BinaryExporter.getInstance(); - - try (final OutputStream out = Files.newOutputStream(toStore)) { - exporter.save(currentModel, out); - } - - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); - } finally { - POST_SAVE_HANDLERS.forEach(currentModel, Consumer::accept); - } - } - - @Override - @FxThread - protected boolean needToolbar() { - return true; - } - - /** - * @return the scaling tool toggle. - */ - @FxThread - private @NotNull ToggleButton getScaleToolButton() { - return notNull(scaleToolButton); - } - - /** - * @return the move tool toggle. - */ - @FxThread - private @NotNull ToggleButton getMoveToolButton() { - return notNull(moveToolButton); - } - - /** - * @return the rotation tool toggle. - */ - @FxThread - private @NotNull ToggleButton getRotationToolButton() { - return notNull(rotationToolButton); - } - - /** - * Switch transformation mode. - */ - @FxThread - private void changeTransformMode(@NotNull final TransformationMode transformationMode) { - - final MA editor3DPart = getEditor3DPart(); - editor3DPart.setTransformMode(transformationMode); - - final ES editorState = getEditorState(); - - if (editorState != null) { - editorState.setTransformationMode(transformationMode.ordinal()); - } - } - - /** - * Switch transformation type. - */ - @FxThread - private void updateTransformTool(@NotNull final TransformType transformType, @NotNull final Boolean newValue) { - - final MA editor3DPart = getEditor3DPart(); - final ToggleButton scaleToolButton = getScaleToolButton(); - final ToggleButton moveToolButton = getMoveToolButton(); - final ToggleButton rotationToolButton = getRotationToolButton(); - - if (newValue != Boolean.TRUE) { - if (editor3DPart.getTransformType() == transformType) { - if (transformType == TransformType.MOVE_TOOL) { - moveToolButton.setSelected(true); - } else if (transformType == TransformType.ROTATE_TOOL) { - rotationToolButton.setSelected(true); - } else if (transformType == TransformType.SCALE_TOOL) { - scaleToolButton.setSelected(true); - } - } - return; - } - - final ES editorState = getEditorState(); - editor3DPart.setTransformType(transformType); - - if (transformType == TransformType.MOVE_TOOL) { - rotationToolButton.setSelected(false); - scaleToolButton.setSelected(false); - } else if (transformType == TransformType.ROTATE_TOOL) { - moveToolButton.setSelected(false); - scaleToolButton.setSelected(false); - } else if (transformType == TransformType.SCALE_TOOL) { - rotationToolButton.setSelected(false); - moveToolButton.setSelected(false); - } - - if (editorState != null) { - editorState.setTransformationType(transformType.ordinal()); - } - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - createActions(container); - - final Label transformModeLabel = new Label(Messages.MODEL_FILE_EDITOR_TRANSFORM_MODE + ":"); - - transformModeComboBox = new ComboBox<>(TRANSFORMATION_MODES); - transformModeComboBox.getSelectionModel() - .selectedItemProperty() - .addListener((observable, oldValue, newValue) -> changeTransformMode(newValue)); - - FXUtils.addToPane(transformModeLabel, container); - FXUtils.addToPane(transformModeComboBox, container); - } - - @FxThread - protected void createActions(@NotNull final HBox container) { - FXUtils.addToPane(createSaveAction(), container); - - selectionButton = new ToggleButton(); - selectionButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SELECTION)); - selectionButton.setGraphic(new ImageView(Icons.CUBE_16)); - selectionButton.setSelected(true); - selectionButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeSelectionVisible(newValue)); - - gridButton = new ToggleButton(); - gridButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_GRID)); - gridButton.setGraphic(new ImageView(Icons.PLANE_16)); - gridButton.setSelected(true); - gridButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeGridVisible(newValue)); - - statisticsButton = new ToggleButton(); - statisticsButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_STATISTICS)); - statisticsButton.setGraphic(new ImageView(Icons.STATISTICS_16)); - statisticsButton.setSelected(true); - statisticsButton.selectedProperty().addListener((observable, oldValue, newValue) -> - changeStatisticsVisible(newValue)); - - moveToolButton = new ToggleButton(); - moveToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_MOVE_TOOL + " (G)")); - moveToolButton.setGraphic(new ImageView(Icons.MOVE_16)); - moveToolButton.setSelected(true); - moveToolButton.selectedProperty().addListener((observable, oldValue, newValue) -> - updateTransformTool(TransformType.MOVE_TOOL, newValue)); - - rotationToolButton = new ToggleButton(); - rotationToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_ROTATION_TOOL + " (R)")); - rotationToolButton.setGraphic(new ImageView(Icons.ROTATION_16)); - rotationToolButton.selectedProperty().addListener((observable, oldValue, newValue) -> - updateTransformTool(TransformType.ROTATE_TOOL, newValue)); - - scaleToolButton = new ToggleButton(); - scaleToolButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SCALE_TOOL + " (S)")); - scaleToolButton.setGraphic(new ImageView(Icons.SCALE_16)); - scaleToolButton.selectedProperty().addListener((observable, oldValue, newValue) -> - updateTransformTool(TransformType.SCALE_TOOL, newValue)); - - DynamicIconSupport.addSupport(selectionButton, gridButton, statisticsButton, moveToolButton, rotationToolButton, - scaleToolButton); - - FXUtils.addClassesTo(selectionButton, gridButton, statisticsButton, moveToolButton, rotationToolButton, - scaleToolButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); - - FXUtils.addToPane(selectionButton, container); - FXUtils.addToPane(gridButton, container); - FXUtils.addToPane(statisticsButton, container); - FXUtils.addToPane(moveToolButton, container); - FXUtils.addToPane(rotationToolButton, container); - FXUtils.addToPane(scaleToolButton, container); - } - - @Override - @FxThread - protected void createContent(@NotNull final StackPane root) { - this.selectionNodeHandler = this::selectNodesFromTree; - - propertyEditorObjectsContainer = new VBox(); - modelNodeTreeEditingContainer = new VBox(); - modelNodeTreeObjectsContainer = new VBox(); - - paintingComponentContainer = new PaintingComponentContainer(this, this); - - scriptingComponent = new EditorScriptingComponent(this::refreshTree); - scriptingComponent.prefHeightProperty().bind(root.heightProperty()); - - super.createContent(root); - - final StackPane editorAreaPane = getEditorAreaPane(); - - statsContainer = new VBox(); - statsContainer.setMouseTransparent(true); - statsContainer.prefHeightProperty().bind(editorAreaPane.heightProperty()); - - modelNodeTree = new ModelNodeTree(selectionNodeHandler, this); - modelNodeTree.prefHeightProperty().bind(root.heightProperty()); - - modelPropertyEditor = new ModelPropertyEditor(this); - modelPropertyEditor.prefHeightProperty().bind(root.heightProperty()); - - FXUtils.addToPane(statsContainer, editorAreaPane); - FXUtils.addClassTo(statsContainer, CssClasses.SCENE_EDITOR_STATS_CONTAINER); - FXUtils.addClassTo(modelNodeTree.getTreeView(), CssClasses.TRANSPARENT_TREE_VIEW); - } - - @Override - @FxThread - protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { - super.createToolComponents(container, root); - - container.addComponent(buildSplitComponent(getModelNodeTreeObjectsContainer(), getPropertyEditorObjectsContainer(), root), - Messages.SCENE_FILE_EDITOR_TOOL_OBJECTS); - container.addComponent(buildSplitComponent(getModelNodeTreeEditingContainer(), getPaintingComponentContainer(), root), - Messages.SCENE_FILE_EDITOR_TOOL_PAINTING); - container.addComponent(getScriptingComponent(), Messages.SCENE_FILE_EDITOR_TOOL_SCRIPTING); - } - - /** - * Refresh tree. - */ - @FxThread - protected void refreshTree() { - getModelNodeTree().fill(notNull(getCurrentModel())); - } - - /** - * Process change tool. - * - * @param oldValue the old value - * @param newValue the new value - */ - @FxThread - protected void processChangeTool(@Nullable final Number oldValue, @NotNull final Number newValue) { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - final PaintingComponentContainer editingComponentContainer = getPaintingComponentContainer(); - - final VBox propertyEditorParent = (VBox) modelPropertyEditor.getParent(); - final VBox modelNodeTreeParent = (VBox) modelNodeTree.getParent(); - - if (propertyEditorParent != null) { - FXUtils.removeFromParent(modelPropertyEditor, propertyEditorParent); - } - - if (modelNodeTreeParent != null) { - FXUtils.removeFromParent(modelNodeTree, modelNodeTreeParent); - } - - final int oldIndex = oldValue == null ? -1 : oldValue.intValue(); - final int newIndex = newValue.intValue(); - - final VBox propertyContainer = getPropertyEditorObjectsContainer(); - - if (newIndex == OBJECTS_TOOL) { - FXUtils.addToPane(modelPropertyEditor, propertyContainer); - FXUtils.addToPane(modelNodeTree, getModelNodeTreeObjectsContainer()); - selectNodesFromTree(modelNodeTree.getSelectedItems()); - } else if (newIndex == PAINTING_TOOL) { - FXUtils.addToPane(modelNodeTree, getModelNodeTreeEditingContainer()); - editingComponentContainer.notifyShowed(); - } - - if (oldIndex == PAINTING_TOOL) { - editingComponentContainer.notifyHided(); - } - - final MA editor3DPart = getEditor3DPart(); - editor3DPart.changePaintingMode(newIndex == PAINTING_TOOL); - } - - @Override - @FxThread - protected void handleDragDroppedEvent(@NotNull final DragEvent dragEvent) { - super.handleDragDroppedEvent(dragEvent); - - UiUtils.handleDroppedFile(dragEvent, FileExtensions.JME_OBJECT, this, - dragEvent, AbstractSceneFileEditor::addNewModel); - - UiUtils.handleDroppedFile(dragEvent, FileExtensions.JME_MATERIAL, this, - dragEvent, AbstractSceneFileEditor::applyMaterial); - } - - @Override - @FxThread - protected void handleDragOverEvent(@NotNull final DragEvent dragEvent) { - super.handleDragOverEvent(dragEvent); - UiUtils.acceptIfHasFile(dragEvent, ACCEPTED_FILES); - } - - /** - * Apply a new material from an asset tree. - * - * @param dragEvent the drag event. - * @param file the file. - */ - @FxThread - private void applyMaterial(@NotNull final DragEvent dragEvent, @NotNull final Path file) { - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - final MA editor3DState = getEditor3DPart(); - final MaterialKey materialKey = new MaterialKey(assetPath); - final Camera camera = editor3DState.getCamera(); - - final BorderPane area = get3DArea(); - final Point2D areaPoint = area.sceneToLocal(dragEvent.getSceneX(), dragEvent.getSceneY()); - - EXECUTOR_MANAGER.addJmeTask(() -> { - - final Geometry geometry = editor3DState.getGeometryByScreenPos((float) areaPoint.getX(), - camera.getHeight() - (float) areaPoint.getY()); - - if (geometry == null) return; - final Object linkNode = findParent(geometry, AssetLinkNode.class::isInstance); - if (linkNode != null) return; - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material material = assetManager.loadAsset(materialKey); - - final PropertyOperation operation = - new PropertyOperation<>(geometry, Messages.MODEL_PROPERTY_MATERIAL, material, geometry.getMaterial()); - - operation.setApplyHandler(Geometry::setMaterial); - - execute(operation); - }); - } - - /** - * Add a new model from an asset tree. - * - * @param dragEvent the drag event. - * @param file the file. - */ - @FxThread - private void addNewModel(@NotNull final DragEvent dragEvent, @NotNull final Path file) { - - final M currentModel = getCurrentModel(); - if (!(currentModel instanceof Node)) { - return; - } - - final ModelNodeTree nodeTree = getModelNodeTree(); - final Object selected = nodeTree.getSelectedObject(); - - final Node parent; - - if (selected instanceof Node && - nodeTree.getSelectedCount() == 1 && - findParent((Spatial) selected, AssetLinkNode.class::isInstance) == null) { - parent = (Node) selected; - } else { - parent = (Node) currentModel; - } - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - final MA editor3DPart = getEditor3DPart(); - final ModelKey modelKey = new ModelKey(assetPath); - final Camera camera = editor3DPart.getCamera(); - - final BorderPane area = get3DArea(); - final Point2D areaPoint = area.sceneToLocal(dragEvent.getSceneX(), dragEvent.getSceneY()); - - EXECUTOR_MANAGER.addJmeTask(() -> { - - final SceneLayer defaultLayer = getDefaultLayer(this); - final LocalObjects local = LocalObjects.get(); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Spatial loadedModel = assetManager.loadModel(modelKey); - - final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); - assetLinkNode.attachLinkedChild(loadedModel, modelKey); - assetLinkNode.setUserData(KEY_LOADED_MODEL, true); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, assetLinkNode); - } - - final Vector3f scenePoint = editor3DPart.getScenePosByScreenPos((float) areaPoint.getX(), - camera.getHeight() - (float) areaPoint.getY()); - final Vector3f result = local.nextVector(scenePoint) - .subtractLocal(parent.getWorldTranslation()); - - final boolean isPhysics = NodeUtils.children(loadedModel) - .flatMap(ControlUtils::controls) - .anyMatch(PhysicsControl.class::isInstance); - - if (isPhysics) { - - NodeUtils.updateWorldBound(loadedModel); - - final BoundingVolume worldBound = loadedModel.getWorldBound(); - - float height = 0; - - if (worldBound instanceof BoundingBox) { - height = ((BoundingBox) worldBound).getYExtent(); - height = Math.min(((BoundingBox) worldBound).getXExtent(), height); - height = Math.min(((BoundingBox) worldBound).getZExtent(), height); - } else if (worldBound instanceof BoundingSphere) { - height = ((BoundingSphere) worldBound).getRadius(); - } - - height /= 2F; - - final Quaternion localRotation = assetLinkNode.getLocalRotation(); - final Vector3f up = GeomUtils.getUp(localRotation, local.nextVector()); - up.multLocal(height); - - result.addLocal(up); - } - - - assetLinkNode.setLocalTranslation(result); - - execute(new AddChildOperation(assetLinkNode, parent, false)); - }); - } - - - /** - * Handle changing select visibility. - */ - @FxThread - private void changeSelectionVisible(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - final MA editor3DPart = getEditor3DPart(); - editor3DPart.updateShowSelection(newValue); - - final ES editorState = getEditorState(); - if (editorState != null) { - editorState.setEnableSelection(newValue); - } - } - - /** - * Handle changing grid visibility. - */ - @FxThread - private void changeGridVisible(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - final MA editor3DPart = getEditor3DPart(); - editor3DPart.updateShowGrid(newValue); - - final ES editorState = getEditorState(); - if (editorState != null) { - editorState.setEnableGrid(newValue); - } - } - - /** - * Handle changing statistics visibility. - */ - @FxThread - private void changeStatisticsVisible(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) { - return; - } - - stats3DPart.setEnabled(newValue); - - final ES editorState = getEditorState(); - if (editorState != null) { - editorState.setShowStatistics(newValue); - } - } - - /** - * Notify about transformed the object. - * - * @param spatial the spatial - */ - @FromAnyThread - public void notifyTransformed(@NotNull final Spatial spatial) { - EXECUTOR_MANAGER.addFxTask(() -> notifyTransformedImpl(spatial)); - } - - /** - * Notify about transformed the object. - */ - @FxThread - private void notifyTransformedImpl(@NotNull final Spatial spatial) { - - Object toUpdate = spatial; - - if (spatial instanceof WrapperNode) { - toUpdate = ((WrapperNode) spatial).getWrappedObject(); - } - - final ModelPropertyEditor propertyEditor = getModelPropertyEditor(); - propertyEditor.syncFor(toUpdate); - } - - @Override - @JmeThread - public @NotNull Node getCursorNode() { - return getEditor3DPart().getCursorNode(); - } - - @Override - @JmeThread - public @NotNull Node getMarkersNode() { - return getEditor3DPart().getMarkersNode(); - } -} - diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java deleted file mode 100644 index d9b659ce..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java +++ /dev/null @@ -1,738 +0,0 @@ -package com.ss.editor.ui.component.editor.impl.scene; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.ScenePresentable; -import com.ss.editor.extension.scene.app.state.EditableSceneAppState; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.extension.scene.filter.EditableSceneFilter; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.part3d.editor.impl.scene.SceneEditor3DPart; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.editor.EditorDescription; -import com.ss.editor.ui.component.editor.impl.AbstractFileEditor; -import com.ss.editor.ui.component.editor.state.EditorState; -import com.ss.editor.ui.component.editor.state.impl.EditorSceneEditorState; -import com.ss.editor.ui.component.tab.EditorToolComponent; -import com.ss.editor.ui.control.app.state.list.AppStateList; -import com.ss.editor.ui.control.filter.list.FilterList; -import com.ss.editor.ui.control.layer.LayerNodeTree; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.model.ModelPropertyEditor; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.MaterialUtils; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.control.ToggleButton; -import javafx.scene.control.Tooltip; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Objects; -import java.util.function.Supplier; - -/** - * The implementation of the {@link AbstractFileEditor} for working with {@link SceneNode}. - * - * @author JavaSaBr - */ -public class SceneFileEditor extends AbstractSceneFileEditor - implements SceneChangeConsumer { - - private static final int LAYERS_TOOL = 3; - private static final int APP_STATES_TOOL = 4; - private static final int FILTERS_TOOL = 5; - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final EditorDescription DESCRIPTION = new EditorDescription(); - - static { - DESCRIPTION.setEditorName(Messages.SCENE_FILE_EDITOR_NAME); - DESCRIPTION.setConstructor(SceneFileEditor::new); - DESCRIPTION.setEditorId(SceneFileEditor.class.getSimpleName()); - DESCRIPTION.addExtension(FileExtensions.JME_SCENE); - } - - /** - * The list with app states. - */ - @Nullable - private AppStateList appStateList; - - /** - * The list with filters. - */ - @Nullable - private FilterList filterList; - - /** - * The tree with layers. - */ - @Nullable - private LayerNodeTree layerNodeTree; - - /** - * The light toggle. - */ - @Nullable - private ToggleButton lightButton; - - /** - * The audio toggle. - */ - @Nullable - private ToggleButton audioButton; - - /** - * The container of property editor in app states tool. - */ - @Nullable - private VBox propertyEditorAppStateContainer; - - /** - * The container of property editor in filters tool. - */ - @Nullable - private VBox propertyEditorFiltersContainer; - - /** - * The container of property editor in layers tool. - */ - @Nullable - private VBox propertyEditorLayersContainer; - - /** - * The flag of sync selection. - */ - private boolean needSyncSelection; - - private SceneFileEditor() { - setNeedSyncSelection(true); - } - - @Override - @FxThread - protected @NotNull SceneEditor3DPart create3DEditorPart() { - return new SceneEditor3DPart(this); - } - - @Override - @FxThread - protected @Nullable Supplier getEditorStateFactory() { - return EditorSceneEditorState::new; - } - - @Override - @FxThread - protected void doOpenFile(@NotNull final Path file) throws IOException { - super.doOpenFile(file); - - final Path assetFile = notNull(getAssetFile(file), "Asset file for " + file + " can't be null."); - final ModelKey modelKey = new ModelKey(toAssetPath(assetFile)); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - Spatial loadedScene = assetManager.loadAsset(modelKey); - - final SceneNode model = (SceneNode) loadedScene; - model.depthFirstTraversal(this::updateVisibility); - - MaterialUtils.cleanUpMaterialParams(model); - - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.openModel(model); - - handleAddedObject(model); - - setCurrentModel(model); - setIgnoreListeners(true); - try { - refreshTree(); - } finally { - setIgnoreListeners(false); - } - } - - @Override - @FxThread - protected void refreshTree() { - super.refreshTree(); - - final SceneNode model = getCurrentModel(); - - final AppStateList appStateList = getAppStateList(); - appStateList.fill(model); - - final FilterList filterList = getFilterList(); - filterList.fill(model); - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.fill(new LayersRoot(this)); - } - - @FxThread - private void updateVisibility(@NotNull final Spatial spatial) { - final SceneLayer layer = SceneLayer.getLayer(spatial); - if (layer != null) { - spatial.setVisible(layer.isShowed()); - } - } - - /** - * Get the list with app states. - * - * @return the list with app states. - */ - @FxThread - private @NotNull AppStateList getAppStateList() { - return notNull(appStateList); - } - - /** - * Get the list with filters. - * - * @return the list with filters. - */ - @FxThread - private @NotNull FilterList getFilterList() { - return notNull(filterList); - } - - /** - * Get the tree with layers. - * - * @return the tree with layers. - */ - @FxThread - private @NotNull LayerNodeTree getLayerNodeTree() { - return notNull(layerNodeTree); - } - - /** - * Get the container of property editor in layers tool. - * - * @return the container of property editor in layers tool. - */ - @FxThread - private @NotNull VBox getPropertyEditorLayersContainer() { - return notNull(propertyEditorLayersContainer); - } - - /** - * Get the container of property editor in filters tool. - * - * @return the container of property editor in filters tool. - */ - @FxThread - private @NotNull VBox getPropertyEditorFiltersContainer() { - return notNull(propertyEditorFiltersContainer); - } - - @Override - @FxThread - protected boolean isNeedToOpenObjectsTool(final int current) { - return !(current == OBJECTS_TOOL || current == LAYERS_TOOL || current == SCRIPTING_TOOL); - } - - /** - * Get the container of property editor in app states tool. - * - * @return the container of property editor in app states tool. - */ - @FxThread - private @NotNull VBox getPropertyEditorAppStateContainer() { - return notNull(propertyEditorAppStateContainer); - } - - @Override - @FxThread - protected void createToolbar(@NotNull final HBox container) { - super.createToolbar(container); - - lightButton = new ToggleButton(); - lightButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SHOW_LIGHTS)); - lightButton.setGraphic(new ImageView(Icons.LIGHT_16)); - lightButton.setSelected(true); - lightButton.selectedProperty().addListener((observable, oldValue, newValue) -> changeLight(newValue)); - - audioButton = new ToggleButton(); - audioButton.setTooltip(new Tooltip(Messages.SCENE_FILE_EDITOR_ACTION_SHOW_AUDIO)); - audioButton.setGraphic(new ImageView(Icons.AUDIO_16)); - audioButton.setSelected(true); - audioButton.selectedProperty().addListener((observable, oldValue, newValue) -> changeAudio(newValue)); - - DynamicIconSupport.addSupport(lightButton, audioButton); - - FXUtils.addClassesTo(lightButton, audioButton, CssClasses.FILE_EDITOR_TOOLBAR_BUTTON); - - FXUtils.addToPane(lightButton, container); - FXUtils.addToPane(audioButton, container); - } - - /** - * Handle changing light models visibility. - */ - @FxThread - private void changeLight(@NotNull final Boolean newValue) { - - if (isIgnoreListeners()) { - return; - } - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.updateLightShowed(newValue); - - if (editorState != null) { - editorState.setShowedLight(newValue); - } - } - - /** - * Handle changing audio models visibility. - */ - @FxThread - private void changeAudio(@NotNull final Boolean newValue) { - - if (isIgnoreListeners()) { - return; - } - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.updateAudioShowed(newValue); - - if (editorState != null) { - editorState.setShowedAudio(newValue); - } - } - - @Override - @FxThread - protected void createContent(@NotNull final StackPane root) { - - appStateList = new AppStateList(this::selectAppStateFromList, this); - propertyEditorAppStateContainer = new VBox(); - - filterList = new FilterList(this::selectFilterFromList, this); - propertyEditorFiltersContainer = new VBox(); - - layerNodeTree = new LayerNodeTree(this::selectNodeFromLayersTree, this); - propertyEditorLayersContainer = new VBox(); - - super.createContent(root); - - FXUtils.addClassTo(layerNodeTree.getTreeView(), CssClasses.TRANSPARENT_TREE_VIEW); - } - - @Override - @FxThread - protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { - super.createToolComponents(container, root); - - container.addComponent(buildSplitComponent(getLayerNodeTree(), getPropertyEditorLayersContainer(), root), - Messages.SCENE_FILE_EDITOR_TOOL_LAYERS); - container.addComponent(buildSplitComponent(getAppStateList(), getPropertyEditorAppStateContainer(), root), - Messages.SCENE_FILE_EDITOR_TOOL_APP_STATES); - container.addComponent(buildSplitComponent(getFilterList(), getPropertyEditorFiltersContainer(), root), - Messages.SCENE_FILE_EDITOR_TOOL_FILTERS); - } - - @Override - @FxThread - protected void processChangeTool(@Nullable final Number oldValue, @NotNull final Number newValue) { - super.processChangeTool(oldValue, newValue); - - final int newIndex = newValue.intValue(); - if (newIndex < 2) { - return; - } - - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - final VBox appStateContainer = getPropertyEditorAppStateContainer(); - final VBox filtersContainer = getPropertyEditorFiltersContainer(); - final VBox layersContainer = getPropertyEditorLayersContainer(); - - switch (newIndex) { - case LAYERS_TOOL: { - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - final TreeNode selected = layerNodeTree.getSelected(); - FXUtils.addToPane(modelPropertyEditor, layersContainer); - selectNodeFromLayersTree(selected); - break; - } - case APP_STATES_TOOL: { - final AppStateList appStateList = getAppStateList(); - FXUtils.addToPane(modelPropertyEditor, appStateContainer); - selectAppStateFromList(appStateList.getSelected()); - break; - } - case FILTERS_TOOL: { - final FilterList filterList = getFilterList(); - FXUtils.addToPane(modelPropertyEditor, filtersContainer); - selectFilterFromList(filterList.getSelected()); - break; - } - } - } - - /** - * Get the light toggle. - * - * @return the light toggle. - */ - @FxThread - private @NotNull ToggleButton getLightButton() { - return notNull(lightButton); - } - - /** - * Get the audio toggle. - * - * @return the audio toggle. - */ - @FxThread - private @NotNull ToggleButton getAudioButton() { - return notNull(audioButton); - } - - @Override - @FxThread - protected void loadState() { - super.loadState(); - - final EditorSceneEditorState editorState = notNull(getEditorState()); - getLightButton().setSelected(editorState.isShowedLight()); - getAudioButton().setSelected(editorState.isShowedAudio()); - } - - /** - * Handle the selected app state from the list. - */ - @FxThread - private void selectAppStateFromList(@Nullable final EditableSceneAppState appState) { - - if (!isNeedSyncSelection()) { - return; - } - - setNeedSyncSelection(false); - try { - super.selectNodeFromTree(appState); - } finally { - setNeedSyncSelection(true); - } - } - - /** - * Handle the selected filter from the list. - */ - @FxThread - private void selectFilterFromList(@Nullable final EditableSceneFilter sceneFilter) { - - if (!isNeedSyncSelection()) { - return; - } - - setNeedSyncSelection(false); - try { - super.selectNodeFromTree(sceneFilter); - } finally { - setNeedSyncSelection(true); - } - } - - /** - * Handle the selected object from the layers tree. - */ - @FxThread - private void selectNodeFromLayersTree(@Nullable final Object object) { - - if (!isNeedSyncSelection()) { - return; - } - - setNeedSyncSelection(false); - try { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.selectSingle(object); - - selectNodeFromTree(object); - - } finally { - setNeedSyncSelection(true); - } - } - - @Override - @FxThread - public void selectNodesFromTree(@NotNull final Array objects) { - - if (!isNeedSyncSelection()) { - super.selectNodesFromTree(objects); - return; - } - - setNeedSyncSelection(false); - try { - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.selects(objects); - - super.selectNodesFromTree(objects); - - } finally { - setNeedSyncSelection(true); - } - } - - @Override - @FromAnyThread - public @NotNull EditorDescription getDescription() { - return DESCRIPTION; - } - - /** - * Return true if need sync selection. - * - * @param needSyncSelection true if need sync selection. - */ - @FxThread - private void setNeedSyncSelection(final boolean needSyncSelection) { - this.needSyncSelection = needSyncSelection; - } - - /** - * Return true if need sync selection. - * - * @return true if need sync selection. - */ - @FxThread - private boolean isNeedSyncSelection() { - return needSyncSelection; - } - - @Override - protected boolean canSelect(@NotNull final Spatial spatial) { - return !(spatial instanceof SceneNode) && !(spatial instanceof SceneLayer) && super.canSelect(spatial); - } - - @Override - @FxThread - protected void handleAddedObject(@NotNull final Spatial model) { - super.handleAddedObject(model); - - if (!(model instanceof SceneNode)) { - return; - } - - final SceneNode sceneNode = (SceneNode) model; - final SceneEditor3DPart editor3DState = getEditor3DPart(); - - sceneNode.getFilters().stream() - .filter(ScenePresentable.class::isInstance) - .forEach(filter -> editor3DState.addPresentable((ScenePresentable) filter)); - sceneNode.getAppStates().stream() - .filter(ScenePresentable.class::isInstance) - .forEach(state -> editor3DState.addPresentable((ScenePresentable) state)); - } - - @Override - @FxThread - protected void handleRemovedObject(@NotNull final Spatial model) { - super.handleRemovedObject(model); - - if (!(model instanceof SceneNode)) { - return; - } - - final SceneNode sceneNode = (SceneNode) model; - final SceneEditor3DPart editor3DState = getEditor3DPart(); - - sceneNode.getFilters().stream() - .filter(ScenePresentable.class::isInstance) - .forEach(filter -> editor3DState.removePresentable((ScenePresentable) filter)); - sceneNode.getAppStates().stream() - .filter(ScenePresentable.class::isInstance) - .forEach(state -> editor3DState.removePresentable((ScenePresentable) state)); - } - - @Override - @FxThread - public void notifyFxAddedChild(@NotNull final Object parent, @NotNull final Object added, final int index, - final boolean needSelect) { - super.notifyFxAddedChild(parent, added, index, needSelect); - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - - if (parent instanceof LayersRoot) { - layerNodeTree.notifyAdded(parent, added, index); - } else if (added instanceof Spatial) { - layerNodeTree.notifyAdded((Spatial) added); - } - - EXECUTOR_MANAGER.addJmeTask(() -> getCurrentModel().notifyAdded(added)); - } - - @Override - @FxThread - public void notifyFxRemovedChild(@NotNull final Object parent, @NotNull final Object removed) { - super.notifyFxRemovedChild(parent, removed); - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - - if (parent instanceof LayersRoot) { - layerNodeTree.notifyRemoved(parent, removed); - } else if (removed instanceof Spatial) { - layerNodeTree.notifyRemoved((Spatial) removed); - } - - EXECUTOR_MANAGER.addJmeTask(() -> getCurrentModel().notifyRemoved(removed)); - } - - @Override - @FxThread - public void notifyFxChangeProperty(@Nullable final Object parent, @NotNull final Object object, - @NotNull final String propertyName) { - super.notifyFxChangeProperty(parent, object, propertyName); - - if (object instanceof Spatial && Objects.equals(propertyName, SceneLayer.KEY)) { - - final Spatial spatial = (Spatial) object; - final SceneLayer layer = SceneLayer.getLayer(spatial); - - if (layer == null) { - spatial.setVisible(true); - } else { - spatial.setVisible(layer.isShowed()); - } - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.notifyChangedLayer(spatial, layer); - } - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.notifyChanged(null, object); - - if (!(object instanceof EditableProperty)) { - return; - } - - final EditableProperty property = (EditableProperty) object; - final Object editObject = property.getObject(); - - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - modelPropertyEditor.syncFor(editObject); - } - - @Override - @FxThread - public void notifyAddedAppState(@NotNull final SceneAppState appState) { - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.addAppState(appState); - - if (appState instanceof ScenePresentable) { - editor3DPart.addPresentable((ScenePresentable) appState); - } - - getAppStateList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyRemovedAppState(@NotNull final SceneAppState appState) { - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.removeAppState(appState); - - if (appState instanceof ScenePresentable) { - editor3DPart.removePresentable((ScenePresentable) appState); - } - - getAppStateList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyChangedAppState(@NotNull final SceneAppState appState) { - getAppStateList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyAddedFilter(@NotNull final SceneFilter sceneFilter) { - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.addFilter(sceneFilter); - - if (sceneFilter instanceof ScenePresentable) { - editor3DPart.addPresentable((ScenePresentable) sceneFilter); - } - - getFilterList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyRemovedFilter(@NotNull final SceneFilter sceneFilter) { - - final SceneEditor3DPart editor3DPart = getEditor3DPart(); - editor3DPart.removeFilter(sceneFilter); - - if (sceneFilter instanceof ScenePresentable) { - editor3DPart.removePresentable((ScenePresentable) sceneFilter); - } - - getFilterList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyChangedFilter(@NotNull final SceneFilter sceneFilter) { - getFilterList().fill(getCurrentModel()); - } - - @Override - @FxThread - public void notifyHided() { - super.notifyHided(); - EXECUTOR_MANAGER.addJmeTask(EditorUtil::enableGlobalLightProbe); - } - - @Override - @FxThread - public void notifyShowed() { - super.notifyShowed(); - EXECUTOR_MANAGER.addJmeTask(EditorUtil::disableGlobalLightProbe); - } - - @Override - public String toString() { - return "SceneFileEditor{} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/scripting/EditorScriptingComponent.java b/src/main/java/com/ss/editor/ui/component/editor/scripting/EditorScriptingComponent.java deleted file mode 100644 index b114d9b5..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/scripting/EditorScriptingComponent.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.ss.editor.ui.component.editor.scripting; - -import com.ss.editor.Messages; -import com.ss.editor.ui.component.scripting.GroovyEditorComponent; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import groovy.lang.GroovyShell; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; -import org.jetbrains.annotations.NotNull; - -/** - * The component to work with scripts in an editor. - * - * @author JavaSaBr - */ -public class EditorScriptingComponent extends GridPane { - - /** - * The table of variables. - */ - @NotNull - private final ObjectDictionary variables; - - /** - * The list of imports. - */ - @NotNull - private final Array imports; - - /** - * The shell. - */ - @NotNull - private final GroovyShell shell; - - /** - * The header component. - */ - @NotNull - private final GroovyEditorComponent headerComponent; - - /** - * The editor component. - */ - @NotNull - private final GroovyEditorComponent editorComponent; - - /** - * The apply handler. - */ - @NotNull - private final Runnable applyHandler; - - /** - * Instantiates a new Editor scripting component. - * - * @param applyHandler the apply handler - */ - public EditorScriptingComponent(@NotNull final Runnable applyHandler) { - this.applyHandler = applyHandler; - - this.editorComponent = new GroovyEditorComponent(true); - this.editorComponent.setFocusTraversable(true); - this.editorComponent.prefHeightProperty().bind(heightProperty().multiply(0.6)); - this.editorComponent.prefWidthProperty().bind(widthProperty()); - this.headerComponent = new GroovyEditorComponent(false); - this.headerComponent.prefHeightProperty().bind(heightProperty().multiply(0.4)); - this.headerComponent.prefWidthProperty().bind(widthProperty()); - this.shell = new GroovyShell(); - this.variables = DictionaryFactory.newObjectDictionary(); - this.imports = ArrayFactory.newArray(String.class); - - final Label headersLabel = new Label(Messages.EDITOR_SCRIPTING_COMPONENT_HEADERS + ":"); - final Label scriptBodyLabel = new Label(Messages.EDITOR_SCRIPTING_COMPONENT_BODY + ":"); - - final Button runButton = new Button(Messages.EDITOR_SCRIPTING_COMPONENT_RUN); - runButton.setOnAction(event -> run()); - - add(headersLabel, 0, 0, 1, 1); - add(headerComponent, 0, 1, 1, 1); - add(scriptBodyLabel, 0, 2, 1, 1); - add(editorComponent, 0, 3, 1, 1); - add(runButton, 0, 4, 1, 1); - - FXUtils.addClassTo(this, CssClasses.EDITOR_SCRIPTING_COMPONENT); - } - - /** - * Add a global variable to the script. - * - * @param name the name of the variable. - * @param value the variable. - */ - public void addVariable(@NotNull final String name, @NotNull final Object value) { - variables.put(name, value); - addImport(value.getClass()); - } - - /** - * Add an import of a some type. - * - * @param type the type. - */ - public void addImport(@NotNull final Class type) { - final String name = type.getName(); - if (!imports.contains(name)) imports.add(name); - } - - /** - * Build a header of a script. - */ - public void buildHeader() { - - final StringBuilder result = new StringBuilder(); - - imports.forEach(result, (type, stringBuilder) -> stringBuilder.append("import ").append(type).append('\n')); - - result.append('\n'); - - variables.forEach((name, value) -> result.append(value.getClass().getSimpleName()) - .append(' ') - .append(name) - .append(" = load_") - .append(name) - .append("();\n")); - - headerComponent.setCode(result.toString()); - } - - /** - * Set an example of groovy code. - * - * @param example the example code. - */ - public void setExampleCode(@NotNull final String example) { - editorComponent.setCode(example); - } - - /** - * Run the current script. - */ - private void run() { - - String code = editorComponent.getCode(); - - for (final String type : imports) { - final String check = "import " + type; - if (code.contains(check)) { - code = code.replace(check, ""); - } - } - - final StringBuilder result = new StringBuilder(); - - imports.forEach(result, (type, stringBuilder) -> stringBuilder.append("import ").append(type).append('\n')); - result.append(code); - - variables.forEach(shell, GroovyShell::setVariable); - - try { - shell.evaluate(result.toString()); - } catch (final Exception e) { - EditorUtil.handleException(null, this, e); - return; - } - - applyHandler.run(); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/EditorState.java b/src/main/java/com/ss/editor/ui/component/editor/state/EditorState.java deleted file mode 100644 index 8eaacb32..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/state/EditorState.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.component.editor.state; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.impl.AdditionalEditorState; -import org.jetbrains.annotations.NotNull; - -import java.io.Serializable; -import java.util.function.Supplier; - -/** - * The interface for implementing a state container of Editor. - * - * @author JavaSaBr - */ -public interface EditorState extends Serializable { - - /** - * Sets change handler. - * - * @param handle the change handler. - */ - @FxThread - void setChangeHandler(@NotNull Runnable handle); - - /** - * Get or create an additional editor state which will store state in this state. - * - * @param type the type of additional state. - * @param factory the factory of the state if it will not be exists. - * @param the type of the state. - * @return the additional editor state. - */ - @FxThread - @NotNull T getOrCreateAdditionalState(@NotNull Class type, - @NotNull Supplier factory); -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/AdditionalEditorState.java b/src/main/java/com/ss/editor/ui/component/editor/state/impl/AdditionalEditorState.java deleted file mode 100644 index e581069f..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/AdditionalEditorState.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ss.editor.ui.component.editor.state.impl; - -import com.ss.editor.ui.component.editor.state.EditorState; - -/** - * The interface to implement additional state of an editor. - * - * @author JavaSaBr - */ -public interface AdditionalEditorState extends EditorState { -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DEditorState.java b/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DEditorState.java deleted file mode 100644 index 2598e8ef..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DEditorState.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.ss.editor.ui.component.editor.state.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.FastMath; -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -/** - * The base implementation of a state container for an 3D editor. - * - * @author JavaSaBr - */ -public class Editor3DEditorState extends AbstractEditorState { - - /** - * The constant serialVersionUID. - */ - public static final long serialVersionUID = 1; - - /** - * The camera location. - */ - @Nullable - protected volatile Vector3f cameraLocation; - - /** - * The vertical camera rotation. - */ - protected volatile float cameraVRotation; - - /** - * The horizontal camera rotation. - */ - protected volatile float cameraHRotation; - - /** - * The camera speed. - */ - protected volatile float cameraSpeed; - - /** - * The camera zoom. - */ - protected volatile float cameraTDistance; - - public Editor3DEditorState() { - this.cameraLocation = new Vector3f(); - this.cameraVRotation = FastMath.PI / 6; - this.cameraTDistance = 20; - this.cameraHRotation = 0; - this.cameraSpeed = 1; - } - - /** - * Sets camera h rotation. - * - * @param cameraHRotation the new horizontal rotation. - */ - @FxThread - public void setCameraHRotation(final float cameraHRotation) { - final boolean changed = getCameraHRotation() != cameraHRotation; - this.cameraHRotation = cameraHRotation; - if (changed) notifyChange(); - } - - /** - * Gets camera h rotation. - * - * @return the horizontal camera rotation. - */ - @FxThread - public float getCameraHRotation() { - return cameraHRotation; - } - - /** - * Sets camera location. - * - * @param cameraLocation the new camera position. - */ - @FxThread - public void setCameraLocation(@NotNull final Vector3f cameraLocation) { - final boolean changed = Objects.equals(getCameraLocation(), cameraLocation); - getCameraLocation().set(cameraLocation); - if (changed) notifyChange(); - } - - /** - * Gets camera location. - * - * @return the camera location. - */ - @FxThread - public @NotNull Vector3f getCameraLocation() { - if (cameraLocation == null) cameraLocation = new Vector3f(); - return notNull(cameraLocation); - } - - /** - * Sets camera t distance. - * - * @param cameraTDistance the new camera zoom. - */ - @FxThread - public void setCameraTDistance(final float cameraTDistance) { - final boolean changed = getCameraTDistance() != cameraTDistance; - this.cameraTDistance = cameraTDistance; - if (changed) notifyChange(); - } - - /** - * Gets camera t distance. - * - * @return the camera zoom. - */ - @FxThread - public float getCameraTDistance() { - return cameraTDistance; - } - - /** - * Set the camera speed. - * - * @param cameraSpeed the camera speed. - */ - @FxThread - public void setCameraSpeed(final float cameraSpeed) { - final boolean changed = getCameraSpeed() != cameraSpeed; - this.cameraSpeed = cameraSpeed; - if (changed) notifyChange(); - } - - /** - * Get the camera speed. - * - * @return the camera speed. - */ - @FxThread - public float getCameraSpeed() { - return cameraSpeed; - } - - /** - * Sets camera v rotation. - * - * @param cameraVRotation the new vertical rotation. - */ - @FxThread - public void setCameraVRotation(final float cameraVRotation) { - final boolean changed = getCameraVRotation() != cameraVRotation; - this.cameraVRotation = cameraVRotation; - if (changed) notifyChange(); - } - - /** - * Gets camera v rotation. - * - * @return the vertical camera rotation. - */ - @FxThread - public float getCameraVRotation() { - return cameraVRotation; - } - - @Override - public String toString() { - return "Editor3DEditorState{" + "cameraLocation=" + cameraLocation + ", cameraVRotation=" + cameraVRotation + - ", cameraHRotation=" + cameraHRotation + ", cameraSpeed=" + cameraSpeed + ", cameraTDistance=" + - cameraTDistance + '}'; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DWithEditorToolEditorState.java b/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DWithEditorToolEditorState.java deleted file mode 100644 index 48152415..00000000 --- a/src/main/java/com/ss/editor/ui/component/editor/state/impl/Editor3DWithEditorToolEditorState.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.ss.editor.ui.component.editor.state.impl; - -import static java.lang.Math.abs; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.EditorToolConfig; - -/** - * The base implementation of a state container for an 3D editor with editor tool. - * - * @author JavaSaBr - */ -public class Editor3DWithEditorToolEditorState extends Editor3DEditorState implements EditorToolConfig { - - /** - * The constant serialVersionUID. - */ - public static final long serialVersionUID = 1; - - /** - * The width of tool split panel. - */ - protected volatile int toolWidth; - - /** - * The flag of collapsing split panel. - */ - protected volatile boolean toolCollapsed; - - /** - * Opened editor tool. - */ - private volatile int openedTool; - - /** - * Instantiates a new Abstract editor state. - */ - public Editor3DWithEditorToolEditorState() { - this.toolWidth = 250; - this.toolCollapsed = false; - openedTool = 0; - } - - @Override - @FxThread - public int getToolWidth() { - return toolWidth; - } - - @Override - @FxThread - public void setToolWidth(final int toolWidth) { - final boolean changed = abs(getToolWidth() - toolWidth) > 3; - this.toolWidth = toolWidth; - if (changed) notifyChange(); - } - - @Override - @FxThread - public boolean isToolCollapsed() { - return toolCollapsed; - } - - @Override - @FxThread - public void setToolCollapsed(final boolean toolCollapsed) { - final boolean changed = isToolCollapsed() != toolCollapsed; - this.toolCollapsed = toolCollapsed; - if (changed) notifyChange(); - } - - /** - * Gets opened tool. - * - * @return the opened tool. - */ - public int getOpenedTool() { - return openedTool; - } - - /** - * Sets opened tool. - * - * @param openedTool the opened tool. - */ - public void setOpenedTool(final int openedTool) { - final boolean changed = getOpenedTool() != openedTool; - this.openedTool = openedTool; - final Runnable changeHandler = getChangeHandler(); - if (changed && changeHandler != null) { - changeHandler.run(); - } - } - - @Override - public String toString() { - return "Editor3DWithEditorToolEditorState{" + "toolWidth=" + toolWidth + ", toolCollapsed=" + toolCollapsed + - ", cameraLocation=" + cameraLocation + ", cameraVRotation=" + cameraVRotation + ", cameraHRotation=" + - cameraHRotation + ", cameraSpeed=" + cameraSpeed + ", cameraTDistance=" + cameraTDistance + '}'; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java b/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java deleted file mode 100644 index cbefaa2b..00000000 --- a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.ui.component.painting; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.painting.spawn.SpawnPaintingComponent; -import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Function; - -/** - * The registry of all painting components. - * - * @author JavaSaBr - */ -public class PaintingComponentRegistry { - - private static final PaintingComponentRegistry INSTANCE = new PaintingComponentRegistry(); - - @FromAnyThread - public static @NotNull PaintingComponentRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of painting component's constructors. - */ - @NotNull - private final Array> constructors; - - private PaintingComponentRegistry() { - this.constructors = ArrayFactory.newArray(Function.class); - register(TerrainPaintingComponent::new); - register(SpawnPaintingComponent::new); - } - - /** - * Register the new painting component's constructor. - * - * @param constructor the new painting component's constructor. - */ - @FxThread - public void register(@NotNull Function constructor) { - this.constructors.add(constructor); - } - - /** - * Create all available painting components. - * - * @param container painting component's container. - * @return all available painting components. - */ - @FxThread - public @NotNull Array createComponents(@NotNull PaintingComponentContainer container) { - - var result = ArrayFactory.newArray(PaintingComponent.class); - - constructors.forEach(result, container, - (constructor, components, cont) -> components.add(constructor.apply(cont))); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java b/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java deleted file mode 100644 index c6bc6e4c..00000000 --- a/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ss.editor.ui.component.painting.impl; - -/** - * The enum of brush types. - * - * @author JavaSaBr - */ -public enum PaintingBrushType { - /** - * Sphere brush type. - */ - SPHERE, -} diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTreeCell.java b/src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTreeCell.java deleted file mode 100644 index 51b5f321..00000000 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/VirtualResourceTreeCell.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.ss.editor.ui.component.virtual.tree; - -import static com.ss.editor.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE; -import com.ss.editor.manager.FileIconManager; -import com.ss.editor.ui.component.virtual.tree.resource.FolderVirtualResourceElement; -import com.ss.editor.ui.component.virtual.tree.resource.VirtualResourceElement; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.control.TreeCell; -import javafx.scene.control.TreeView; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The implementation of the cell for {@link TreeView} to show resource. - * - * @author JavaSaBr - */ -public class VirtualResourceTreeCell extends TreeCell> { - - /** - * The icon manager. - */ - @NotNull - private static final FileIconManager ICON_MANAGER = FileIconManager.getInstance(); - - /** - * The icon. - */ - @NotNull - private final ImageView icon; - - protected VirtualResourceTreeCell() { - this.icon = new ImageView(); - } - - @Override - protected void updateItem(@Nullable final VirtualResourceElement item, boolean empty) { - super.updateItem(item, empty); - - if (item == null) { - setText(StringUtils.EMPTY); - setGraphic(null); - return; - } - - final Path file = Paths.get(item.getPath()); - final boolean folder = item instanceof FolderVirtualResourceElement; - - icon.setImage(ICON_MANAGER.getIcon(file, folder, false, DEFAULT_FILE_ICON_SIZE)); - - setText(item.getName()); - setGraphic(icon); - } -} diff --git a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/RootVirtualResourceElement.java b/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/RootVirtualResourceElement.java deleted file mode 100644 index eed6d7a1..00000000 --- a/src/main/java/com/ss/editor/ui/component/virtual/tree/resource/RootVirtualResourceElement.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.ss.editor.ui.component.virtual.tree.resource; - -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; -import org.jetbrains.annotations.NotNull; - -/** - * The root implementation of the virtual resource element. - * - * @author JavaSaBr - */ -public class RootVirtualResourceElement extends FolderVirtualResourceElement { - - public RootVirtualResourceElement(@NotNull final VirtualResourceTree resourceTree) { - super(resourceTree, "/"); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java b/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java deleted file mode 100644 index 92058467..00000000 --- a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.ss.editor.ui.control.app.state.list; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.app.state.EditableSceneAppState; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.dialog.CreateSceneAppStateDialog; -import com.ss.editor.model.undo.impl.RemoveAppStateOperation; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.fx.util.FXUtils; -import javafx.collections.ObservableList; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.control.MultipleSelectionModel; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Consumer; - -/** - * The component to show and to edit app states. - * - * @author JavaSaBr - */ -public class AppStateList extends VBox { - - /** - * The selection handler. - */ - @NotNull - private final Consumer selectHandler; - - /** - * The changes consumer. - */ - @NotNull - private final SceneChangeConsumer changeConsumer; - - /** - * The list view with created scene app states. - */ - @Nullable - private ListView listView; - - public AppStateList(@NotNull final Consumer selectHandler, - @NotNull final SceneChangeConsumer changeConsumer) { - this.changeConsumer = changeConsumer; - this.selectHandler = selectHandler; - createComponents(); - FXUtils.addClassTo(this, CssClasses.SCENE_APP_STATE_CONTAINER); - } - - /** - * Create components of this component. - */ - @FxThread - private void createComponents() { - - listView = new ListView<>(); - listView.setCellFactory(param -> new AppStateListCell(this)); - listView.setEditable(false); - listView.setFocusTraversable(true); - listView.prefHeightProperty().bind(heightProperty()); - listView.prefWidthProperty().bind(widthProperty()); - listView.setFixedCellSize(FxConstants.LIST_CELL_HEIGHT); - - final MultipleSelectionModel selectionModel = listView.getSelectionModel(); - selectionModel.selectedItemProperty().addListener((observable, oldValue, newValue) -> - selectHandler.accept(newValue)); - - final Button addButton = new Button(); - addButton.setGraphic(new ImageView(Icons.ADD_12)); - addButton.setOnAction(event -> addAppState()); - - final Button removeButton = new Button(); - removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); - removeButton.setOnAction(event -> removeAppState()); - removeButton.disableProperty().bind(selectionModel.selectedItemProperty().isNull()); - - final HBox buttonContainer = new HBox(addButton, removeButton); - - FXUtils.addToPane(listView, this); - FXUtils.addToPane(buttonContainer, this); - - FXUtils.addClassTo(buttonContainer, CssClasses.DEF_HBOX); - FXUtils.addClassTo(addButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER); - FXUtils.addClassTo(removeButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER); - FXUtils.addClassTo(listView, CssClasses.TRANSPARENT_LIST_VIEW); - - DynamicIconSupport.addSupport(addButton, removeButton); - } - - /** - * Fill a list of app states. - * - * @param sceneNode the scene node - */ - @FxThread - public void fill(@NotNull final SceneNode sceneNode) { - - final ListView listView = getListView(); - final MultipleSelectionModel selectionModel = listView.getSelectionModel(); - final EditableSceneAppState selected = selectionModel.getSelectedItem(); - - final ObservableList items = listView.getItems(); - items.clear(); - - final List appStates = sceneNode.getAppStates(); - appStates.stream().filter(EditableSceneAppState.class::isInstance) - .map(EditableSceneAppState.class::cast) - .forEach(items::add); - - if (selected != null && appStates.contains(selected)) { - selectionModel.select(selected); - } - } - - /** - * Get the list view with created scene app states. - * - * @return the list view with created scene app states. - */ - @FxThread - private @NotNull ListView getListView() { - return notNull(listView); - } - - /** - * Clear selection. - */ - @FxThread - public void clearSelection() { - final MultipleSelectionModel selectionModel = getListView().getSelectionModel(); - selectionModel.select(null); - } - - /** - * Get the current selected item. - * - * @return the current selected item. - */ - @FxThread - public @Nullable EditableSceneAppState getSelected() { - final MultipleSelectionModel selectionModel = getListView().getSelectionModel(); - return selectionModel.getSelectedItem(); - } - - /** - * Handle adding a new app state. - */ - @FxThread - private void addAppState() { - final CreateSceneAppStateDialog dialog = new CreateSceneAppStateDialog(changeConsumer); - dialog.show(); - } - - /** - * Handle removing an old app state. - */ - @FxThread - private void removeAppState() { - - final MultipleSelectionModel selectionModel = getListView().getSelectionModel(); - final EditableSceneAppState appState = selectionModel.getSelectedItem(); - final SceneNode sceneNode = changeConsumer.getCurrentModel(); - - changeConsumer.execute(new RemoveAppStateOperation(appState, sceneNode)); - } - - /** - * Get the change consumer. - * - * @return the changes consumer. - */ - @FromAnyThread - public @NotNull SceneChangeConsumer getChangeConsumer() { - return changeConsumer; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateListCell.java b/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateListCell.java deleted file mode 100644 index 2ff41d0d..00000000 --- a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateListCell.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.ss.editor.ui.control.app.state.list; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.app.state.EditableSceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.model.undo.impl.DisableAppStateOperation; -import com.ss.editor.model.undo.impl.EnableAppStateOperation; -import com.ss.editor.ui.control.list.AbstractListCell; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of list cell to present an editable scene app state. - * - * @author JavaSaBr - */ -public class AppStateListCell extends AbstractListCell { - - /** - * The list of app states. - */ - @NotNull - private final AppStateList stateList; - - public AppStateListCell(@NotNull final AppStateList stateList) { - this.stateList = stateList; - FXUtils.addClassTo(this, CssClasses.SCENE_APP_STATE_LIST_CELL); - } - - /** - * Get the list of app states. - * - * @return the list of app states. - */ - @FxThread - private @NotNull AppStateList getStateList() { - return stateList; - } - - @Override - @FxThread - protected void processHideImpl() { - - final EditableSceneAppState item = getItem(); - final AppStateList stateList = getStateList(); - final SceneChangeConsumer changeConsumer = stateList.getChangeConsumer(); - - if (item.isEnabled()) { - changeConsumer.execute(new DisableAppStateOperation(item)); - } else { - changeConsumer.execute(new EnableAppStateOperation(item)); - } - } - - @Override - @FxThread - protected boolean isEnabled(@Nullable final EditableSceneAppState item) { - return item != null && item.isEnabled(); - } - - @Override - @FxThread - protected @NotNull String getName(@Nullable final EditableSceneAppState item) { - return item == null ? "" : item.getName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/filter/list/FilterListCell.java b/src/main/java/com/ss/editor/ui/control/filter/list/FilterListCell.java deleted file mode 100644 index eb951fac..00000000 --- a/src/main/java/com/ss/editor/ui/control/filter/list/FilterListCell.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.ss.editor.ui.control.filter.list; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.filter.EditableSceneFilter; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.model.undo.impl.DisableSceneFilterOperation; -import com.ss.editor.model.undo.impl.EnableSceneFilterOperation; -import com.ss.editor.ui.control.list.AbstractListCell; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of list cell to present an editable scene filter. - * - * @author JavaSaBr - */ -public class FilterListCell extends AbstractListCell { - - /** - * The list of filters. - */ - @NotNull - private final FilterList stateList; - - /** - * Instantiates a new Filter list cell. - * - * @param stateList the state list - */ - public FilterListCell(@NotNull final FilterList stateList) { - this.stateList = stateList; - FXUtils.addClassTo(this, CssClasses.SCENE_FILTER_LIST_CELL); - } - - /** - * @return the list of app states. - */ - @NotNull - private FilterList getStateList() { - return stateList; - } - - @FxThread - @Override - protected void processHideImpl() { - - final EditableSceneFilter item = getItem(); - final FilterList stateList = getStateList(); - final SceneChangeConsumer changeConsumer = stateList.getChangeConsumer(); - - if (item.isEnabled()) { - changeConsumer.execute(new DisableSceneFilterOperation(item)); - } else { - changeConsumer.execute(new EnableSceneFilterOperation(item)); - } - } - - @FxThread - @Override - protected boolean isEnabled(@Nullable final EditableSceneFilter item) { - return item != null && item.isEnabled(); - } - - @NotNull - @Override - protected String getName(@Nullable final EditableSceneFilter item) { - return item == null ? "" : item.getName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTreeCell.java b/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTreeCell.java deleted file mode 100644 index 186930a2..00000000 --- a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTreeCell.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ss.editor.ui.control.layer; - -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTreeCell; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of {@link NodeTreeCell} to show layer nodes. - * - * @author JavaSaBr - */ -public class LayerNodeTreeCell extends NodeTreeCell { - - public LayerNodeTreeCell(@NotNull final LayerNodeTree nodeTree) { - super(nodeTree); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/list/AbstractListCell.java b/src/main/java/com/ss/editor/ui/control/list/AbstractListCell.java deleted file mode 100644 index 420bfd68..00000000 --- a/src/main/java/com/ss/editor/ui/control/list/AbstractListCell.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.ss.editor.ui.control.list; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.control.Label; -import javafx.scene.control.cell.TextFieldListCell; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of list cell. - * - * @author JavaSaBr - */ -public abstract class AbstractListCell extends TextFieldListCell { - - /** - * The content box. - */ - @NotNull - private final HBox content; - - /** - * The label of this cell. - */ - @NotNull - private final Label text; - - /** - * The visible icon. - */ - @NotNull - private final ImageView visibleIcon; - - public AbstractListCell() { - this.content = new HBox(); - this.text = new Label(); - this.visibleIcon = new ImageView(); - this.visibleIcon.addEventFilter(MouseEvent.MOUSE_RELEASED, this::processHide); - this.visibleIcon.setOnMouseReleased(this::processHide); - this.visibleIcon.setPickOnBounds(true); - - FXUtils.addToPane(visibleIcon, content); - FXUtils.addToPane(text, content); - - setEditable(false); - - FXUtils.addClassTo(content, CssClasses.DEF_HBOX); - } - - /** - * Update hide status. - */ - @FxThread - private void processHide(@NotNull final MouseEvent event) { - event.consume(); - - if (event.getButton() != MouseButton.PRIMARY) { - return; - } - - processHideImpl(); - } - - /** - * Process to hide. - */ - @FxThread - protected abstract void processHideImpl(); - - @Override - @FxThread - public void updateItem(@Nullable final T item, final boolean empty) { - super.updateItem(item, empty); - - if (item == null) { - setText(StringUtils.EMPTY); - setGraphic(null); - return; - } - - visibleIcon.setVisible(true); - visibleIcon.setManaged(true); - visibleIcon.setImage(!isEnabled(item) ? Icons.INVISIBLE_16 : Icons.VISIBLE_16); - visibleIcon.setOpacity(!isEnabled(item) ? 0.5D : 1D); - - DynamicIconSupport.updateListener(this, visibleIcon, selectedProperty()); - - text.setText(getName(item)); - - setText(StringUtils.EMPTY); - setGraphic(content); - } - - /** - * Get the name of the item. - * - * @param item the item. - * @return the name. - */ - @FxThread - protected abstract @NotNull String getName(@Nullable final T item); - - /** - * @param item the item which needs to check. - * @return true if the item is enabled. - */ - @FxThread - protected abstract boolean isEnabled(@Nullable final T item); -} diff --git a/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java b/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java deleted file mode 100644 index 98502acd..00000000 --- a/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.control.model; - -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.multi.RemoveElementsAction; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.control.SelectionMode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; - -/** - * The implementation of {@link NodeTree} to present a structure of model in an editor. - * - * @author JavaSaBr - */ -public class ModelNodeTree extends NodeTree { - - static { - register(RemoveElementsAction.ACTION_FILLER); - } - - public ModelNodeTree(@NotNull final Consumer> selectionHandler, - @Nullable final ModelChangeConsumer consumer) { - super(selectionHandler, consumer, SelectionMode.MULTIPLE); - } - - public ModelNodeTree(@NotNull final Consumer> selectionHandler, - @Nullable final ModelChangeConsumer consumer, @NotNull final SelectionMode selectionMode) { - super(selectionHandler, consumer, selectionMode); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/model/ModelPropertyEditor.java b/src/main/java/com/ss/editor/ui/control/model/ModelPropertyEditor.java deleted file mode 100644 index 8a14fc5d..00000000 --- a/src/main/java/com/ss/editor/ui/control/model/ModelPropertyEditor.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.ss.editor.ui.control.model; - -import static com.ss.editor.util.NodeUtils.findParent; -import com.jme3.material.Material; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.PropertyEditor; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; - -/** - * The component to contains property controls in the editor. - * - * @author JavaSaBr - */ -public class ModelPropertyEditor extends PropertyEditor { - - /** - * The list of additional 'isNeedUpdate' checkers. - */ - @NotNull - private static final Array> IS_NEED_UPDATE_CHECKERS = ArrayFactory.newArray(BiPredicate.class); - - /** - * The list of additional 'canEdit' checkers. - */ - @NotNull - private static final Array> CAN_EDIT_CHECKERS = ArrayFactory.newArray(BiPredicate.class); - - /** - * Register the additional checker which checks a current object and a checked object and - * returns true if need to update this in the property editor. - * - * @param checker the additional checker. - */ - @FxThread - public static void registerIsNeedUpdateChecker(@NotNull final BiPredicate<@Nullable Object, @Nullable Object> checker) { - IS_NEED_UPDATE_CHECKERS.add(checker); - } - - /** - * Register the additional checker which checks a checked object and its parent and - * returns false if we can't edit this in the property editor. - * - * @param checker the additional checker. - */ - @FxThread - public static void registerCanEditChecker(@NotNull final BiPredicate<@Nullable Object, @Nullable Object> checker) { - CAN_EDIT_CHECKERS.add(checker.negate()); - } - - public ModelPropertyEditor(@NotNull final ModelChangeConsumer changeConsumer) { - super(changeConsumer); - } - - @Override - @FxThread - protected boolean isNeedUpdate(@Nullable final Object object) { - return IS_NEED_UPDATE_CHECKERS.search(getCurrentObject(), object, BiPredicate::test) != null || - super.isNeedUpdate(object); - } - - @Override - @FxThread - protected boolean canEdit(@NotNull final Object object, @Nullable final Object parent) { - - if (object instanceof Control) { - return true; - } else if (object instanceof Material) { - final Material material = (Material) object; - if (material.getKey() != null) return false; - } else if (object instanceof Spatial) { - final Object linkNode = findParent((Spatial) object, AssetLinkNode.class::isInstance); - return linkNode == null || linkNode == object; - } else if (parent instanceof Spatial) { - final Object linkNode = findParent((Spatial) parent, AssetLinkNode.class::isInstance); - return linkNode == null; - } else if (CAN_EDIT_CHECKERS.search(object, parent, BiPredicate::test) != null) { - return false; - } - - return super.canEdit(object, parent); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java b/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java deleted file mode 100644 index 9045a133..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.ss.editor.ui.control.property; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.control.UpdatableControl; -import com.ss.editor.ui.control.property.builder.PropertyBuilderRegistry; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ScrollPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The component to contains property controls in the editor. - * - * @param the type of {@link ChangeConsumer} - * @author JavaSaBr - */ -public class PropertyEditor extends ScrollPane { - - private static final PropertyBuilderRegistry BUILDER_REGISTRY = PropertyBuilderRegistry.getInstance(); - - /** - * The consumer of changes. - */ - @NotNull - private final C changeConsumer; - - /** - * The container of controls. - */ - @Nullable - private VBox container; - - /** - * The current editable object. - */ - @Nullable - private Object currentObject; - - /** - * The current parent. - */ - @Nullable - private Object currentParent; - - public PropertyEditor(@NotNull C changeConsumer) { - this.changeConsumer = changeConsumer; - createComponents(); - } - - /** - * Get the container of controls. - * - * @return the container of controls. - */ - @FxThread - private @NotNull VBox getContainer() { - return notNull(container); - } - - /** - * Create components. - */ - @FxThread - private void createComponents() { - this.container = new VBox(); - this.container.prefWidthProperty() - .bind(widthProperty().subtract(FxConstants.PROPERTY_LIST_OFFSET)); - - var wrapper = new VBox(container); - - FxUtils.addClass(this, - CssClasses.PROPERTY_EDITOR) - .addClass(wrapper, container, - CssClasses.DEF_VBOX, CssClasses.PROPERTY_EDITOR_CONTAINER); - - setContent(wrapper); - } - - /** - * Sync all property controls. - * - * @param object the object. - */ - @FxThread - public void syncFor(@Nullable Object object) { - - if (!isNeedUpdate(object)) { - return; - } - - var container = getContainer(); - container.setDisable(object == null || !canEdit(object, getCurrentParent())); - container.getChildren().forEach(node -> { - if (node instanceof UpdatableControl) { - ((UpdatableControl) node).sync(); - } - }); - } - - /** - * Sync all property controls. - */ - @FxThread - public void refresh() { - - var object = getCurrentObject(); - if (object == null) { - return; - } - - var container = getContainer(); - container.setDisable(!canEdit(object, getCurrentParent())); - container.getChildren().forEach(node -> { - if (node instanceof UpdatableControl) { - ((UpdatableControl) node).sync(); - } - }); - } - - /** - * Build property controls for the object. - * - * @param object the object - * @param parent the parent - */ - @FxThread - public void buildFor(@Nullable Object object, @Nullable Object parent) { - - if (getCurrentObject() == object) { - return; - } - - var container = getContainer(); - var children = container.getChildren(); - children.clear(); - - if (object != null) { - BUILDER_REGISTRY.buildFor(object, parent, container, changeConsumer); - } - - container.setDisable(object == null || !canEdit(object, parent)); - - setCurrentObject(object); - setCurrentParent(parent); - } - - /** - * Return true if we can edit properties of the object. - * - * @param object the object to edit. - * @param parent the parent. - * @return true if we can edit properties of the object. - */ - @FxThread - protected boolean canEdit(@NotNull Object object, @Nullable Object parent) { - return true; - } - - /** - * Re-build property controls for the object. - * - * @param object the object. - * @param parent the parent. - */ - @FxThread - public void rebuildFor(@Nullable Object object, @Nullable Object parent) { - - if (getCurrentObject() != object) { - return; - } - - var container = getContainer(); - var children = container.getChildren(); - children.clear(); - - if (object != null) { - BUILDER_REGISTRY.buildFor(object, parent, container, changeConsumer); - } - } - - /** - * Rebuild all property controls. - */ - @FxThread - public void rebuild() { - rebuildFor(getCurrentObject(), null); - } - - /** - * Return true if need to update property controls. - * - * @param object the object. - * @return true if need to update property controls. - */ - @FxThread - protected boolean isNeedUpdate(@Nullable Object object) { - - var currentObject = getCurrentObject(); - if (object instanceof EditableProperty) { - return currentObject == ((EditableProperty) object).getObject(); - } - - return currentObject == object; - } - - /** - * Set the current editable object. - * - * @param currentObject the current editable object. - */ - @FxThread - private void setCurrentObject(@Nullable Object currentObject) { - this.currentObject = currentObject; - } - - /** - * Get the current object. - * - * @return the current editable object. - */ - @FxThread - protected @Nullable Object getCurrentObject() { - return currentObject; - } - - /** - * Set the current parent. - * - * @param currentParent the current parent. - */ - @FxThread - protected void setCurrentParent(@Nullable Object currentParent) { - this.currentParent = currentParent; - } - - /** - * Get the current parent. - * - * @return the current parent. - */ - @FxThread - protected @Nullable Object getCurrentParent() { - return currentParent; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java b/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java deleted file mode 100644 index 39bb600f..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.ss.editor.ui.control.property.builder; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.builder.impl.*; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The factory to build property controls for an object. - * - * @author JavaSaBr - */ -public class PropertyBuilderRegistry { - - @NotNull - private static final PropertyBuilderRegistry INSTANCE = new PropertyBuilderRegistry(); - - @FromAnyThread - public static @NotNull PropertyBuilderRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of property builders. - */ - @NotNull - private final Array builders; - - /** - * THe list of filters. - */ - @NotNull - private final Array filters; - - private PropertyBuilderRegistry() { - builders = ArrayFactory.newArray(PropertyBuilder.class); - filters = ArrayFactory.newArray(PropertyBuilderFilter.class); - register(AudioNodePropertyBuilder.getInstance()); - register(ParticleEmitterPropertyBuilder.getInstance()); - register(GeometryPropertyBuilder.getInstance()); - register(LightPropertyBuilder.getInstance()); - register(SpatialPropertyBuilder.getInstance()); - register(SceneAppStatePropertyBuilder.getInstance()); - register(SceneFilterPropertyBuilder.getInstance()); - register(DefaultControlPropertyBuilder.getInstance()); - register(EditableControlPropertyBuilder.getInstance()); - register(CollisionShapePropertyBuilder.getInstance()); - register(PrimitivePropertyBuilder.getInstance()); - register(MeshPropertyBuilder.getInstance()); - register(MaterialPropertyBuilder.getInstance()); - register(ParticleInfluencerPropertyBuilder.getInstance()); - register(EmitterShapePropertyBuilder.getInstance()); - register(MaterialSettingsPropertyBuilder.getInstance()); - } - - /** - * Register a new property builder. - * - * @param builder the property builder. - */ - @FromAnyThread - public void register(@NotNull PropertyBuilder builder) { - builders.add(builder); - builders.sort(PropertyBuilder::compareTo); - } - - /** - * Register a new property builder filter. - * - * @param filter the property builder filter. - */ - @FromAnyThread - public void register(@NotNull PropertyBuilderFilter filter) { - filters.add(filter); - } - - /** - * Build properties controls for the object to the container. - * - * @param object the object to build property controls. - * @param parent the parent of the object. - * @param container the container for containing these controls. - * @param changeConsumer the consumer to work between controls and editor. - */ - @FxThread - public void buildFor( - @NotNull Object object, - @Nullable Object parent, - @NotNull VBox container, - @NotNull ChangeConsumer changeConsumer - ) { - - for (var builder : builders) { - - boolean needSkip = false; - - for (var filter : filters) { - if (filter.skip(builder, object, parent)) { - needSkip = true; - break; - } - } - - if (needSkip) { - continue; - } - - builder.buildFor(object, parent, container, changeConsumer); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/AudioNodePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/AudioNodePropertyBuilder.java deleted file mode 100644 index a87b0c7a..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/AudioNodePropertyBuilder.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioNode; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.AudioKeyPropertyControl; -import com.ss.editor.ui.control.property.impl.BooleanPropertyControl; -import com.ss.editor.ui.control.property.impl.FloatPropertyControl; -import com.ss.editor.ui.control.property.impl.Vector3fPropertyControl; -import com.ss.editor.util.AudioNodeUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiConsumer; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link AudioNode} objects. - * - * @author JavaSaBr - */ -public class AudioNodePropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final BiConsumer AUDIO_APPLY_HANDLER = (audioNode, audioKey) -> { - - var assetManager = EditorUtil.getAssetManager(); - - if (audioKey == null) { - audioNode.setAudioData(null, null); - } else { - var audioData = assetManager.loadAudio(audioKey); - AudioNodeUtils.updateData(audioNode, audioData, audioKey); - } - }; - - @NotNull - private static final PropertyBuilder INSTANCE = new AudioNodePropertyBuilder(); - - /** - * Get the single instance. - * - * @return the single instance. - */ - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private AudioNodePropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl( - @NotNull Object object, - @Nullable Object parent, - @NotNull VBox container, - @NotNull ModelChangeConsumer changeConsumer - ) { - - if (!(object instanceof AudioNode)) return; - - final AudioNode audioNode = (AudioNode) object; - final AudioKey key = AudioNodeUtils.getAudioKey(audioNode); - - final Vector3f velocity = audioNode.getVelocity(); - final Vector3f direction = audioNode.getDirection(); - - final float pitch = audioNode.getPitch(); - final float volume = audioNode.getVolume(); - final float timeOffset = audioNode.getTimeOffset(); - final float maxDistance = audioNode.getMaxDistance(); - final float refDistance = audioNode.getRefDistance(); - final float innerAngle = audioNode.getInnerAngle(); - final float outerAngle = audioNode.getOuterAngle(); - - final boolean looping = audioNode.isLooping(); - final boolean reverbEnabled = audioNode.isReverbEnabled(); - final boolean directional = audioNode.isDirectional(); - final boolean positional = audioNode.isPositional(); - - final BooleanPropertyControl loopControl = new BooleanPropertyControl<>(looping, - Messages.MODEL_PROPERTY_IS_LOOPING, changeConsumer); - - loopControl.setApplyHandler(AudioNode::setLooping); - loopControl.setSyncHandler(AudioNode::isLooping); - loopControl.setEditObject(audioNode); - - final BooleanPropertyControl reverbControl = new BooleanPropertyControl<>(reverbEnabled, - Messages.MODEL_PROPERTY_IS_REVERB, changeConsumer); - - reverbControl.setApplyHandler(AudioNode::setReverbEnabled); - reverbControl.setSyncHandler(AudioNode::isReverbEnabled); - reverbControl.setEditObject(audioNode); - - final BooleanPropertyControl directionalControl = new BooleanPropertyControl<>(directional, - Messages.MODEL_PROPERTY_IS_DIRECTIONAL, changeConsumer); - - directionalControl.setApplyHandler(AudioNode::setDirectional); - directionalControl.setSyncHandler(AudioNode::isDirectional); - directionalControl.setEditObject(audioNode); - - final BooleanPropertyControl positionalControl = new BooleanPropertyControl<>(positional, - Messages.MODEL_PROPERTY_IS_POSITIONAL, changeConsumer); - - positionalControl.setApplyHandler(AudioNode::setPositional); - positionalControl.setSyncHandler(AudioNode::isPositional); - positionalControl.setEditObject(audioNode); - - final FloatPropertyControl pitchControl = new FloatPropertyControl<>(pitch, - Messages.MODEL_PROPERTY_AUDIO_PITCH, changeConsumer); - - pitchControl.setApplyHandler(AudioNode::setPitch); - pitchControl.setSyncHandler(AudioNode::getPitch); - pitchControl.setMinMax(0.5F, 2.0F); - pitchControl.setScrollPower(2F); - pitchControl.setEditObject(audioNode); - - final FloatPropertyControl volumeControl = new FloatPropertyControl<>(volume, - Messages.MODEL_PROPERTY_AUDIO_VOLUME, changeConsumer); - - volumeControl.setApplyHandler(AudioNode::setVolume); - volumeControl.setSyncHandler(AudioNode::getVolume); - volumeControl.setMinMax(0F, Float.MAX_VALUE); - volumeControl.setScrollPower(5F); - volumeControl.setEditObject(audioNode); - - final FloatPropertyControl timeOffsetControl = new FloatPropertyControl<>(timeOffset, - Messages.MODEL_PROPERTY_TIME_OFFSET, changeConsumer); - - timeOffsetControl.setApplyHandler(AudioNode::setTimeOffset); - timeOffsetControl.setSyncHandler(AudioNode::getTimeOffset); - timeOffsetControl.setMinMax(0F, Float.MAX_VALUE); - timeOffsetControl.setEditObject(audioNode); - - final FloatPropertyControl maxDistanceControl = new FloatPropertyControl<>(maxDistance, - Messages.MODEL_PROPERTY_MAX_DISTANCE, changeConsumer); - - maxDistanceControl.setApplyHandler(AudioNode::setMaxDistance); - maxDistanceControl.setSyncHandler(AudioNode::getMaxDistance); - maxDistanceControl.setMinMax(0F, Float.MAX_VALUE); - maxDistanceControl.setEditObject(audioNode); - - final FloatPropertyControl refDistanceControl = new FloatPropertyControl<>(refDistance, - Messages.MODEL_PROPERTY_REF_DISTANCE, changeConsumer); - - refDistanceControl.setApplyHandler(AudioNode::setRefDistance); - refDistanceControl.setSyncHandler(AudioNode::getRefDistance); - refDistanceControl.setMinMax(0F, Float.MAX_VALUE); - refDistanceControl.setEditObject(audioNode); - - final FloatPropertyControl innerAngleControl = new FloatPropertyControl<>(innerAngle, - Messages.MODEL_PROPERTY_INNER_ANGLE, changeConsumer); - - innerAngleControl.setApplyHandler(AudioNode::setInnerAngle); - innerAngleControl.setSyncHandler(AudioNode::getInnerAngle); - innerAngleControl.setEditObject(audioNode); - - final FloatPropertyControl outerAngleControl = new FloatPropertyControl<>(outerAngle, - Messages.MODEL_PROPERTY_OUTER_ANGLE, changeConsumer); - - outerAngleControl.setApplyHandler(AudioNode::setOuterAngle); - outerAngleControl.setSyncHandler(AudioNode::getOuterAngle); - outerAngleControl.setEditObject(audioNode); - - FXUtils.addToPane(loopControl, container); - FXUtils.addToPane(reverbControl, container); - FXUtils.addToPane(directionalControl, container); - FXUtils.addToPane(positionalControl, container); - FXUtils.addToPane(pitchControl, container); - FXUtils.addToPane(volumeControl, container); - FXUtils.addToPane(timeOffsetControl, container); - FXUtils.addToPane(maxDistanceControl, container); - FXUtils.addToPane(refDistanceControl, container); - FXUtils.addToPane(innerAngleControl, container); - FXUtils.addToPane(outerAngleControl, container); - - final AudioKeyPropertyControl audioKeyControl = new AudioKeyPropertyControl<>(key, - Messages.MODEL_PROPERTY_AUDIO_DATA, changeConsumer); - - audioKeyControl.setApplyHandler(AUDIO_APPLY_HANDLER); - audioKeyControl.setSyncHandler(AudioNodeUtils::getAudioKey); - audioKeyControl.setEditObject(audioNode); - - final Vector3fPropertyControl velocityControl = new Vector3fPropertyControl<>(velocity, - Messages.MODEL_PROPERTY_VELOCITY, changeConsumer); - - velocityControl.setApplyHandler(AudioNode::setVelocity); - velocityControl.setSyncHandler(AudioNode::getVelocity); - velocityControl.setEditObject(audioNode); - - final Vector3fPropertyControl directionControl = new Vector3fPropertyControl<>(direction, - Messages.MODEL_PROPERTY_DIRECTION, changeConsumer); - - directionControl.setApplyHandler(AudioNode::setDirection); - directionControl.setSyncHandler(AudioNode::getDirection); - directionControl.setEditObject(audioNode); - - buildSplitLine(container); - - FXUtils.addToPane(audioKeyControl, container); - FXUtils.addToPane(velocityControl, container); - FXUtils.addToPane(directionControl, container); - - buildSplitLine(container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java deleted file mode 100644 index 72a63bce..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java +++ /dev/null @@ -1,250 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.bullet.collision.shapes.*; -import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; -import com.jme3.math.Matrix3f; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.DefaultSinglePropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link CollisionShape} objects. - * - * @author JavaSaBr - */ -public class CollisionShapePropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final PropertyBuilder INSTANCE = new CollisionShapePropertyBuilder(); - - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private CollisionShapePropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, - @NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer) { - - if (object instanceof ChildCollisionShape) { - build((ChildCollisionShape) object, container, changeConsumer); - } - - if (!(object instanceof CollisionShape)) { - return; - } - - if (object instanceof BoxCollisionShape) { - build((BoxCollisionShape) object, container, changeConsumer); - } else if (object instanceof SphereCollisionShape) { - build((SphereCollisionShape) object, container, changeConsumer); - } else if (object instanceof CapsuleCollisionShape) { - build((CapsuleCollisionShape) object, container, changeConsumer); - } else if (object instanceof ConeCollisionShape) { - build((ConeCollisionShape) object, container, changeConsumer); - } else if (object instanceof CylinderCollisionShape) { - build((CylinderCollisionShape) object, container, changeConsumer); - } - - build((CollisionShape) object, container, changeConsumer); - } - - @FxThread - private void build(@NotNull final CylinderCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f halfExtents = shape.getHalfExtents(); - final float margin = shape.getMargin(); - final int axis = shape.getAxis(); - - final DefaultSinglePropertyControl halfExtentsControl = - new DefaultSinglePropertyControl<>(halfExtents, Messages.MODEL_PROPERTY_HALF_EXTENTS, changeConsumer); - - halfExtentsControl.setSyncHandler(CylinderCollisionShape::getHalfExtents); - halfExtentsControl.setToStringFunction(Vector3f::toString); - halfExtentsControl.setEditObject(shape); - - final DefaultSinglePropertyControl marginControl = - new DefaultSinglePropertyControl<>(margin, Messages.MODEL_PROPERTY_MARGIN, changeConsumer); - - marginControl.setSyncHandler(CylinderCollisionShape::getMargin); - marginControl.setToStringFunction(value -> Float.toString(value)); - marginControl.setEditObject(shape); - - final DefaultSinglePropertyControl axisControl = - new DefaultSinglePropertyControl<>(axis, Messages.MODEL_PROPERTY_AXIS, changeConsumer); - - axisControl.setSyncHandler(CylinderCollisionShape::getAxis); - axisControl.setToStringFunction(value -> Integer.toString(value)); - axisControl.setEditObject(shape); - - FXUtils.addToPane(halfExtentsControl, container); - FXUtils.addToPane(marginControl, container); - FXUtils.addToPane(axisControl, container); - } - - private void build(@NotNull final ConeCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final float radius = shape.getRadius(); - final float height = shape.getHeight(); - - final DefaultSinglePropertyControl radiusControl = - new DefaultSinglePropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - - radiusControl.setSyncHandler(ConeCollisionShape::getRadius); - radiusControl.setToStringFunction(value -> Float.toString(value)); - radiusControl.setEditObject(shape); - - final DefaultSinglePropertyControl heightControl = - new DefaultSinglePropertyControl<>(height, Messages.MODEL_PROPERTY_HEIGHT, changeConsumer); - - heightControl.setSyncHandler(ConeCollisionShape::getHeight); - heightControl.setToStringFunction(value -> Float.toString(value)); - heightControl.setEditObject(shape); - - FXUtils.addToPane(radiusControl, container); - FXUtils.addToPane(heightControl, container); - } - - @FxThread - private void build(@NotNull final CapsuleCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final float radius = shape.getRadius(); - final float height = shape.getHeight(); - - final int axis = shape.getAxis(); - - final DefaultSinglePropertyControl radiusControl = - new DefaultSinglePropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - - radiusControl.setSyncHandler(CapsuleCollisionShape::getRadius); - radiusControl.setToStringFunction(value -> Float.toString(value)); - radiusControl.setEditObject(shape); - - final DefaultSinglePropertyControl heightControl = - new DefaultSinglePropertyControl<>(height, Messages.MODEL_PROPERTY_HEIGHT, changeConsumer); - - heightControl.setSyncHandler(CapsuleCollisionShape::getHeight); - heightControl.setToStringFunction(value -> Float.toString(value)); - heightControl.setEditObject(shape); - - final DefaultSinglePropertyControl axisControl = - new DefaultSinglePropertyControl<>(axis, Messages.MODEL_PROPERTY_AXIS, changeConsumer); - - axisControl.setSyncHandler(CapsuleCollisionShape::getAxis); - axisControl.setToStringFunction(value -> Integer.toString(value)); - axisControl.setEditObject(shape); - - FXUtils.addToPane(radiusControl, container); - FXUtils.addToPane(heightControl, container); - FXUtils.addToPane(axisControl, container); - } - - @FxThread - private void build(@NotNull final SphereCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final float radius = shape.getRadius(); - - final DefaultSinglePropertyControl radiusControl = - new DefaultSinglePropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - - radiusControl.setSyncHandler(SphereCollisionShape::getRadius); - radiusControl.setToStringFunction(value -> Float.toString(value)); - radiusControl.setEditObject(shape); - - FXUtils.addToPane(radiusControl, container); - } - - @FxThread - private void build(@NotNull final BoxCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f halfExtents = shape.getHalfExtents(); - - final DefaultSinglePropertyControl halfExtentsControl = - new DefaultSinglePropertyControl<>(halfExtents, Messages.MODEL_PROPERTY_HALF_EXTENTS, changeConsumer); - - halfExtentsControl.setSyncHandler(BoxCollisionShape::getHalfExtents); - halfExtentsControl.setToStringFunction(Vector3f::toString); - halfExtentsControl.setEditObject(shape); - - FXUtils.addToPane(halfExtentsControl, container); - } - - @FxThread - private void build(@NotNull final CollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f scale = shape.getScale(); - final long objectId = shape.getObjectId(); - final float margin = shape.getMargin(); - - final DefaultSinglePropertyControl scaleControl = - new DefaultSinglePropertyControl<>(scale, Messages.MODEL_PROPERTY_SCALE, changeConsumer); - - scaleControl.setSyncHandler(CollisionShape::getScale); - scaleControl.setToStringFunction(Vector3f::toString); - scaleControl.setEditObject(shape); - - final DefaultSinglePropertyControl objectIdControl = - new DefaultSinglePropertyControl<>(objectId, Messages.MODEL_PROPERTY_OBJECT_ID, changeConsumer); - - objectIdControl.setSyncHandler(CollisionShape::getObjectId); - objectIdControl.setToStringFunction(String::valueOf); - objectIdControl.setEditObject(shape); - - final DefaultSinglePropertyControl marginControl = - new DefaultSinglePropertyControl<>(margin, Messages.MODEL_PROPERTY_MARGIN, changeConsumer); - - marginControl.setSyncHandler(CollisionShape::getMargin); - marginControl.setToStringFunction(String::valueOf); - marginControl.setEditObject(shape); - - FXUtils.addToPane(scaleControl, container); - FXUtils.addToPane(marginControl, container); - FXUtils.addToPane(objectIdControl, container); - } - - @FxThread - private void build(@NotNull final ChildCollisionShape shape, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f location = shape.location; - final Matrix3f rotation = shape.rotation; - - final DefaultSinglePropertyControl locationControl = - new DefaultSinglePropertyControl<>(location, Messages.MODEL_PROPERTY_LOCATION, changeConsumer); - - locationControl.setSyncHandler(collisionShape -> collisionShape.location); - locationControl.setToStringFunction(Vector3f::toString); - locationControl.setEditObject(shape); - - final DefaultSinglePropertyControl rotationControl = - new DefaultSinglePropertyControl<>(rotation, Messages.MODEL_PROPERTY_ROTATION, changeConsumer); - - rotationControl.setSyncHandler(collisionShape -> collisionShape.rotation); - rotationControl.setToStringFunction(matrix3f -> new Quaternion().fromRotationMatrix(matrix3f).toString()); - rotationControl.setEditObject(shape); - rotationControl.reload(); - - FXUtils.addToPane(locationControl, container); - FXUtils.addToPane(rotationControl, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/DefaultControlPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/DefaultControlPropertyBuilder.java deleted file mode 100644 index a487bea3..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/DefaultControlPropertyBuilder.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import static com.ss.editor.extension.property.EditablePropertyType.*; -import com.jme3.animation.Animation; -import com.jme3.animation.SkeletonControl; -import com.jme3.bullet.control.BetterCharacterControl; -import com.jme3.bullet.control.PhysicsControl; -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.bullet.objects.PhysicsRigidBody; -import com.jme3.bullet.objects.VehicleWheel; -import com.jme3.cinematic.events.AbstractCinematicEvent; -import com.jme3.cinematic.events.MotionEvent; -import com.jme3.scene.control.AbstractControl; -import com.jme3.scene.control.Control; -import com.jme3.scene.control.LightControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.extension.property.SimpleProperty; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for default controls. - * - * @author JavaSaBr - */ -public class DefaultControlPropertyBuilder extends EditableModelObjectPropertyBuilder { - - public static final int PRIORITY = 0; - - @NotNull - private static final PropertyBuilder INSTANCE = new DefaultControlPropertyBuilder(); - - @FxThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private DefaultControlPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @FxThread - protected @NotNull List> getProperties(@NotNull AbstractControl control) { - - var result = new ArrayList>(); - result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, - AbstractControl::isEnabled, AbstractControl::setEnabled)); - - return result; - } - - @FxThread - protected @NotNull List> getProperties(@NotNull PhysicsControl control) { - - var result = new ArrayList>(); - result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, - PhysicsControl::isEnabled, PhysicsControl::setEnabled)); - - return result; - } - - @Override - @FxThread - protected @Nullable List> getProperties(@NotNull Object object) { - - var properties = new ArrayList>(); - - if (object instanceof VehicleWheel) { - - var control = (VehicleWheel) object; - - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_FRONT, control, - VehicleWheel::isFrontWheel, VehicleWheel::setFrontWheel)); - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, - VehicleWheel::isApplyLocal, VehicleWheel::setApplyLocal)); - properties.add(new SimpleProperty<>(STRING, Messages.MODEL_PROPERTY_OBJECT_ID, control, - wheel -> String.valueOf(wheel.getWheelId()))); - - properties.add(new SimpleProperty<>(SPATIAL_FROM_SCENE, Messages.MODEL_PROPERTY_WHEEL_SPATIAL, control, - VehicleWheel::getWheelSpatial, VehicleWheel::setWheelSpatial)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LOCATION, control, - VehicleWheel::getLocation)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, - VehicleWheel::getDirection)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_AXLE, control, - VehicleWheel::getAxle)); - - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_COMPRESSION, control, - VehicleWheel::getWheelsDampingCompression, VehicleWheel::setWheelsDampingCompression)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION_SLIP, control, - VehicleWheel::getFrictionSlip, VehicleWheel::setFrictionSlip)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, control, - VehicleWheel::getRadius, VehicleWheel::setRadius)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_FORCE, control, - VehicleWheel::getMaxSuspensionForce, VehicleWheel::setMaxSuspensionForce)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, - VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, - VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_RELAXATION, control, - VehicleWheel::getWheelsDampingRelaxation, VehicleWheel::setWheelsDampingRelaxation)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SUSPENSION_STIFFNESS, control, - VehicleWheel::getSuspensionStiffness, VehicleWheel::setSuspensionStiffness)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_REST_LENGTH, control, - VehicleWheel::getRestLength, VehicleWheel::setRestLength)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ROLL_INFLUENCE, control, - VehicleWheel::getRollInfluence, VehicleWheel::setRollInfluence)); - - } else if (object instanceof AbstractCinematicEvent) { - - var control = (AbstractCinematicEvent) object; - - properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_LOOP_MODE, control, - AbstractCinematicEvent::getLoopMode, AbstractCinematicEvent::setLoopMode)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_INITIAL_DURATION, control, - AbstractCinematicEvent::getInitialDuration, AbstractCinematicEvent::setInitialDuration)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SPEED, control, - AbstractCinematicEvent::getSpeed, AbstractCinematicEvent::setSpeed)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_TIME, control, - AbstractCinematicEvent::getTime, AbstractCinematicEvent::setTime)); - - } else if (object instanceof Animation) { - - var animation = (Animation) object; - - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LENGTH, animation, - Animation::getLength)); - } - - if (object instanceof MotionEvent) { - - var control = (MotionEvent) object; - - properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, - MotionEvent::getDirectionType, MotionEvent::setDirectionType)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, - MotionEvent::getDirection, MotionEvent::setDirection)); - properties.add(new SimpleProperty<>(QUATERNION, Messages.MODEL_PROPERTY_ROTATION, control, - MotionEvent::getRotation, MotionEvent::setRotation)); - } - - if (!(object instanceof Control)) { - return properties; - } - - if (object instanceof AbstractControl) { - properties.addAll(getProperties((AbstractControl) object)); - } - - if (object instanceof PhysicsControl) { - properties.addAll(getProperties((PhysicsControl) object)); - } - - if (object instanceof LightControl) { - - var control = (LightControl) object; - - properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, - LightControl::getControlDir, LightControl::setControlDir)); - properties.add(new SimpleProperty<>(LIGHT_FROM_SCENE, Messages.MODEL_PROPERTY_LIGHT, control, - LightControl::getLight, LightControl::setLight)); - - } else if (object instanceof BetterCharacterControl) { - - var control = (BetterCharacterControl) object; - - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, - BetterCharacterControl::getGravity, BetterCharacterControl::setGravity)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_VELOCITY, control, - BetterCharacterControl::getVelocity)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, - BetterCharacterControl::getViewDirection, BetterCharacterControl::setViewDirection)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, - BetterCharacterControl::getWalkDirection, BetterCharacterControl::setWalkDirection)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_JUMP_FORCE, control, - BetterCharacterControl::getJumpForce, BetterCharacterControl::setJumpForce)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, - BetterCharacterControl::getDuckedFactor, BetterCharacterControl::setDuckedFactor)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_PHYSICS_DAMPING, control, - BetterCharacterControl::getPhysicsDamping, BetterCharacterControl::setPhysicsDamping)); - - } else if (object instanceof RigidBodyControl) { - - var control = (RigidBodyControl) object; - - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC_SPATIAL, control, - RigidBodyControl::isKinematicSpatial, RigidBodyControl::setKinematicSpatial)); - - } else if (object instanceof SkeletonControl) { - - var control = (SkeletonControl) object; - - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_HARDWARE_SKINNING_PREFERRED, control, - SkeletonControl::isHardwareSkinningPreferred, SkeletonControl::setHardwareSkinningPreferred)); - - } else if (object instanceof VehicleControl) { - - var control = (VehicleControl) object; - - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, - VehicleControl::isApplyPhysicsLocal, VehicleControl::setApplyPhysicsLocal)); - - } - - if (object instanceof PhysicsRigidBody) { - - var control = (PhysicsRigidBody) object; - - properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC, control, - PhysicsRigidBody::isKinematic, PhysicsRigidBody::setKinematic)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, - PhysicsRigidBody::getGravity, PhysicsRigidBody::setGravity)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LINEAR_FACTOR, control, - PhysicsRigidBody::getLinearFactor, PhysicsRigidBody::setLinearFactor)); - properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_ANGULAR_VELOCITY, control, - PhysicsRigidBody::getAngularVelocity, PhysicsRigidBody::setAngularVelocity)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_DAMPING, control, - PhysicsRigidBody::getAngularDamping, PhysicsRigidBody::setAngularDamping)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_FACTOR, control, - PhysicsRigidBody::getAngularFactor, PhysicsRigidBody::setAngularFactor)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_SLEEPING_THRESHOLD, control, - PhysicsRigidBody::getAngularSleepingThreshold, PhysicsRigidBody::setAngularSleepingThreshold)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION, control, - PhysicsRigidBody::getFriction, PhysicsRigidBody::setFriction)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MASS, control, - PhysicsRigidBody::getMass, PhysicsRigidBody::setMass)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LINEAR_DAMPING, control, - PhysicsRigidBody::getLinearDamping, PhysicsRigidBody::setLinearDamping)); - properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RESTITUTION, control, - PhysicsRigidBody::getRestitution, PhysicsRigidBody::setRestitution)); - } - - return properties; - } - - @Override - public int getPriority() { - return PRIORITY; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java deleted file mode 100644 index 460368ac..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.extension.scene.control.EditableControl; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The property builder to build property controls of editable controls. - * - * @author JavaSaBr - */ -public class EditableControlPropertyBuilder extends EditableModelObjectPropertyBuilder { - - @NotNull - private static final EditableControlPropertyBuilder INSTANCE = new EditableControlPropertyBuilder(); - - @FromAnyThread - public static @NotNull EditableControlPropertyBuilder getInstance() { - return INSTANCE; - } - - private EditableControlPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected @Nullable List> getProperties(@NotNull final Object object) { - if(!(object instanceof EditableControl)) return null; - return ((EditableControl) object).getEditableProperties(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EmitterShapePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EmitterShapePropertyBuilder.java deleted file mode 100644 index 21ddf608..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EmitterShapePropertyBuilder.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.effect.shapes.EmitterBoxShape; -import com.jme3.effect.shapes.EmitterPointShape; -import com.jme3.effect.shapes.EmitterShape; -import com.jme3.effect.shapes.EmitterSphereShape; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.FloatPropertyControl; -import com.ss.editor.ui.control.property.impl.Vector3fPropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link EmitterShape}. - * - * @author JavaSaBr - */ -public class EmitterShapePropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final PropertyBuilder INSTANCE = new EmitterShapePropertyBuilder(); - - /** - * Get the single instance. - * - * @return the single instance - */ - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private EmitterShapePropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, - @NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer) { - - if (!(object instanceof EmitterShape)) return; - - final EmitterShape shape = (EmitterShape) object; - - if (shape instanceof EmitterPointShape) { - createControls(container, changeConsumer, (EmitterPointShape) object); - } else if (shape instanceof EmitterBoxShape) { - createControls(container, changeConsumer, (EmitterBoxShape) object); - } else if (shape instanceof EmitterSphereShape) { - createControls(container, changeConsumer, (EmitterSphereShape) object); - } - } - - /** - * Create controls. - * - * @param container the container. - * @param changeConsumer the change consumer. - * @param shape the shape. - */ - @FxThread - private void createControls(@NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer, - @NotNull final EmitterPointShape shape) { - - final Vector3f point = shape.getPoint(); - - final Vector3fPropertyControl pointControl = - new Vector3fPropertyControl<>(point, Messages.MODEL_PROPERTY_POINT, changeConsumer); - - pointControl.setSyncHandler(EmitterPointShape::getPoint); - pointControl.setApplyHandler(EmitterPointShape::setPoint); - pointControl.setEditObject(shape); - - FXUtils.addToPane(pointControl, container); - } - - /** - * Create controls. - * - * @param container the container. - * @param changeConsumer the change consumer. - * @param shape the shape. - */ - @FxThread - private void createControls(@NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer, - @NotNull final EmitterBoxShape shape) { - - final Vector3f length = shape.getLen(); - final Vector3f min = shape.getMin(); - - final Vector3fPropertyControl lengthControl = - new Vector3fPropertyControl<>(length, Messages.MODEL_PROPERTY_LENGTH, changeConsumer); - - lengthControl.setSyncHandler(EmitterBoxShape::getLen); - lengthControl.setApplyHandler(EmitterBoxShape::setLen); - lengthControl.setEditObject(shape); - - final Vector3fPropertyControl minControl = - new Vector3fPropertyControl<>(min, Messages.MODEL_PROPERTY_MIN, changeConsumer); - - minControl.setSyncHandler(EmitterBoxShape::getMin); - minControl.setApplyHandler(EmitterBoxShape::setMin); - minControl.setEditObject(shape); - - FXUtils.addToPane(lengthControl, container); - FXUtils.addToPane(minControl, container); - } - - /** - * Create controls. - * - * @param container the container. - * @param changeConsumer the change consumer. - * @param shape the shape. - */ - @FxThread - private void createControls(@NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer, - @NotNull final EmitterSphereShape shape) { - - final Vector3f center = shape.getCenter(); - final float radius = shape.getRadius(); - - final FloatPropertyControl radiusControl = - new FloatPropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - - radiusControl.setSyncHandler(EmitterSphereShape::getRadius); - radiusControl.setApplyHandler(EmitterSphereShape::setRadius); - radiusControl.setEditObject(shape); - - final Vector3fPropertyControl centerControl = - new Vector3fPropertyControl<>(center, Messages.MODEL_PROPERTY_CENTER, changeConsumer); - - centerControl.setSyncHandler(EmitterSphereShape::getCenter); - centerControl.setApplyHandler(EmitterSphereShape::setCenter); - centerControl.setEditObject(shape); - - FXUtils.addToPane(centerControl, container); - buildSplitLine(container); - FXUtils.addToPane(radiusControl, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/GeometryPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/GeometryPropertyBuilder.java deleted file mode 100644 index 652fb86b..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/GeometryPropertyBuilder.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import static com.ss.editor.util.EditorUtil.clipNumber; -import com.jme3.asset.AssetManager; -import com.jme3.asset.MaterialKey; -import com.jme3.bounding.BoundingBox; -import com.jme3.bounding.BoundingSphere; -import com.jme3.bounding.BoundingVolume; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.scene.Geometry; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.DefaultPropertyControl; -import com.ss.editor.ui.control.property.impl.LodLevelPropertyControl; -import com.ss.editor.ui.control.property.impl.MaterialKeyPropertyControl; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link Geometry} objects. - * - * @author JavaSaBr - */ -public class GeometryPropertyBuilder extends AbstractPropertyBuilder { - - /** - * The list of additional checkers. - */ - @NotNull - private static final Array> CAN_EDIT_MATERIAL_CHECKERS = ArrayFactory.newArray(Predicate.class); - - /** - * Register the additional checker which should return false if we can't edit material for a geometry. - * - * @param checker the additional checker. - */ - @FxThread - public static void registerCanEditMaterialChecker(@NotNull final Predicate<@NotNull Geometry> checker) { - CAN_EDIT_MATERIAL_CHECKERS.add(checker.negate()); - } - - @NotNull - private static final BiConsumer MATERIAL_APPLY_HANDLER = (geometry, materialKey) -> { - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - if (materialKey == null) { - - final Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - material.setColor("Color", ColorRGBA.Gray); - - geometry.setMaterial(material); - - } else { - final Material material = assetManager.loadAsset(materialKey); - geometry.setMaterial(material); - } - }; - - @NotNull - private static final Function MATERIAL_SYNC_HANDLER = geometry -> { - final Material material = geometry.getMaterial(); - return (MaterialKey) material.getKey(); - }; - - @NotNull - private static final Function BOUNDING_VOLUME_TO_STRING = boundingVolume -> { - - if (boundingVolume instanceof BoundingSphere) { - final BoundingSphere boundingSphere = (BoundingSphere) boundingVolume; - return Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_SPHERE + ": [" + - Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_SPHERE_RADIUS + "=" + boundingSphere.getRadius() + "]"; - } else if (boundingVolume instanceof BoundingBox) { - - final BoundingBox boundingBox = (BoundingBox) boundingVolume; - - final float xExtent = clipNumber(boundingBox.getXExtent(), 100); - final float yExtent = clipNumber(boundingBox.getYExtent(), 100); - final float zExtent = clipNumber(boundingBox.getZExtent(), 100); - - return Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_BOX + - ": [x=" + xExtent + ", y=" + yExtent + ", z=" + zExtent + "]"; - } - - return StringUtils.EMPTY; - }; - - @NotNull - private static final PropertyBuilder INSTANCE = new GeometryPropertyBuilder(); - - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private GeometryPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, - @NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer) { - - if (!(object instanceof Geometry)) return; - - final Geometry geometry = (Geometry) object; - final BoundingVolume modelBound = geometry.getModelBound(); - final int lodLevel = geometry.getLodLevel(); - - final DefaultPropertyControl boundingVolumeControl = - new DefaultPropertyControl<>(modelBound, Messages.BOUNDING_VOLUME_MODEL_PROPERTY_CONTROL_NAME, changeConsumer); - - boundingVolumeControl.setToStringFunction(BOUNDING_VOLUME_TO_STRING); - boundingVolumeControl.reload(); - boundingVolumeControl.setEditObject(geometry); - - if (canEditMaterial(geometry)) { - - final Material material = geometry.getMaterial(); - final MaterialKey materialKey = (MaterialKey) material.getKey(); - - final MaterialKeyPropertyControl materialControl = - new MaterialKeyPropertyControl<>(materialKey, Messages.MODEL_PROPERTY_MATERIAL, changeConsumer); - - materialControl.setApplyHandler(MATERIAL_APPLY_HANDLER); - materialControl.setSyncHandler(MATERIAL_SYNC_HANDLER); - materialControl.setEditObject(geometry); - - FXUtils.addToPane(materialControl, container); - } - - FXUtils.addToPane(boundingVolumeControl, container); - - buildSplitLine(container); - - final LodLevelPropertyControl lodLevelControl = - new LodLevelPropertyControl<>(lodLevel, Messages.MODEL_PROPERTY_LOD, changeConsumer); - - lodLevelControl.setApplyHandler(Geometry::setLodLevel); - lodLevelControl.setSyncHandler(Geometry::getLodLevel); - lodLevelControl.setEditObject(geometry, true); - - FXUtils.addToPane(lodLevelControl, container); - } - - /** - * Can edit material boolean. - * - * @param geometry the geometry. - * @return true if we can editor the material. - */ - @FxThread - private boolean canEditMaterial(@NotNull final Geometry geometry) { - return CAN_EDIT_MATERIAL_CHECKERS.search(geometry, Predicate::test) == null; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/LightPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/LightPropertyBuilder.java deleted file mode 100644 index 27a85a81..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/LightPropertyBuilder.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.light.DirectionalLight; -import com.jme3.light.Light; -import com.jme3.light.PointLight; -import com.jme3.light.SpotLight; -import com.jme3.math.ColorRGBA; -import com.jme3.math.FastMath; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.impl.DirectionLightPropertyControl; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.ColorPropertyControl; -import com.ss.editor.ui.control.property.impl.FloatPropertyControl; -import com.ss.editor.ui.control.property.impl.Vector3fPropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link Light} objects. - * - * @author JavaSaBr - */ -public class LightPropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final PropertyBuilder INSTANCE = new LightPropertyBuilder(); - - /** - * Get the single instance. - * - * @return the single instance. - */ - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private LightPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - if (object instanceof DirectionalLight) { - buildForDirectionLight((DirectionalLight) object, container, changeConsumer); - } else if (object instanceof SpotLight) { - buildForSpotLight((SpotLight) object, container, changeConsumer); - } else if (object instanceof PointLight) { - buildForPointLight((PointLight) object, container, changeConsumer); - } - - if (object instanceof Light) { - buildForLight((Light) object, container, changeConsumer); - } - } - - @FxThread - private void buildForDirectionLight(@NotNull final DirectionalLight light, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f direction = light.getDirection().clone(); - - final DirectionLightPropertyControl directionControl = - new DirectionLightPropertyControl<>(direction, Messages.MODEL_PROPERTY_DIRECTION, changeConsumer); - directionControl.setApplyHandler(DirectionalLight::setDirection); - directionControl.setSyncHandler(DirectionalLight::getDirection); - directionControl.setEditObject(light); - - FXUtils.addToPane(directionControl, container); - - buildSplitLine(container); - } - - @FxThread - private void buildForPointLight(@NotNull final PointLight light, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f position = light.getPosition().clone(); - final float radius = light.getRadius(); - - final Vector3fPropertyControl positionControl = - new Vector3fPropertyControl<>(position, Messages.MODEL_PROPERTY_LOCATION, changeConsumer); - positionControl.setApplyHandler(PointLight::setPosition); - positionControl.setSyncHandler(PointLight::getPosition); - positionControl.setEditObject(light); - - final FloatPropertyControl radiusControl = - new FloatPropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - radiusControl.setApplyHandler(PointLight::setRadius); - radiusControl.setSyncHandler(PointLight::getRadius); - radiusControl.setMinMax(0, Integer.MAX_VALUE); - radiusControl.setEditObject(light); - - FXUtils.addToPane(positionControl, container); - buildSplitLine(container); - FXUtils.addToPane(radiusControl, container); - } - - @FxThread - private void buildForSpotLight(@NotNull final SpotLight light, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f direction = light.getDirection().clone(); - final Vector3f position = light.getPosition().clone(); - - final float innerAngle = light.getSpotInnerAngle(); - final float outerAngle = light.getSpotOuterAngle(); - final float range = light.getSpotRange(); - - final DirectionLightPropertyControl directionControl = - new DirectionLightPropertyControl<>(direction, Messages.MODEL_PROPERTY_DIRECTION, changeConsumer); - directionControl.setApplyHandler(SpotLight::setDirection); - directionControl.setSyncHandler(SpotLight::getDirection); - directionControl.setEditObject(light); - - final Vector3fPropertyControl positionControl = - new Vector3fPropertyControl<>(position, Messages.MODEL_PROPERTY_LOCATION, changeConsumer); - positionControl.setApplyHandler(SpotLight::setPosition); - positionControl.setSyncHandler(SpotLight::getPosition); - positionControl.setEditObject(light); - - final FloatPropertyControl rangeControl = - new FloatPropertyControl<>(range, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - rangeControl.setApplyHandler(SpotLight::setSpotRange); - rangeControl.setSyncHandler(SpotLight::getSpotRange); - rangeControl.setMinMax(0, Integer.MAX_VALUE); - rangeControl.setEditObject(light); - - final FloatPropertyControl innerAngleControl = - new FloatPropertyControl<>(innerAngle, Messages.MODEL_PROPERTY_INNER_ANGLE, changeConsumer); - innerAngleControl.setApplyHandler(SpotLight::setSpotInnerAngle); - innerAngleControl.setSyncHandler(SpotLight::getSpotInnerAngle); - innerAngleControl.setMinMax(0F, FastMath.HALF_PI); - innerAngleControl.setScrollPower(1F); - innerAngleControl.setEditObject(light); - - final FloatPropertyControl outerAngleControl = - new FloatPropertyControl<>(outerAngle, Messages.MODEL_PROPERTY_OUTER_ANGLE, changeConsumer); - outerAngleControl.setApplyHandler(SpotLight::setSpotOuterAngle); - outerAngleControl.setSyncHandler(SpotLight::getSpotOuterAngle); - outerAngleControl.setMinMax(0F, FastMath.HALF_PI); - outerAngleControl.setScrollPower(1F); - outerAngleControl.setEditObject(light); - - FXUtils.addToPane(directionControl, container); - FXUtils.addToPane(positionControl, container); - buildSplitLine(container); - FXUtils.addToPane(rangeControl, container); - FXUtils.addToPane(innerAngleControl, container); - FXUtils.addToPane(outerAngleControl, container); - } - - @FxThread - private void buildForLight(@NotNull final Light object, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final ColorRGBA color = object.getColor(); - - final ColorPropertyControl radiusControl = - new ColorPropertyControl<>(color, Messages.MODEL_PROPERTY_COLOR, changeConsumer); - radiusControl.setApplyHandler(Light::setColor); - radiusControl.setSyncHandler(Light::getColor); - radiusControl.setEditObject(object); - - FXUtils.addToPane(radiusControl, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MeshPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/MeshPropertyBuilder.java deleted file mode 100644 index 580941fd..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MeshPropertyBuilder.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.DefaultSinglePropertyControl; -import com.ss.editor.ui.control.property.impl.EnumPropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link Mesh} objects. - * - * @author JavaSaBr - */ -public class MeshPropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final Mesh.Mode[] MODES = Mesh.Mode.values(); - - @NotNull - private static final PropertyBuilder INSTANCE = new MeshPropertyBuilder(); - - /** - * Get the single instance. - * - * @return the single instance - */ - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private MeshPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - if (!(object instanceof Mesh)) return; - - final Mesh mesh = (Mesh) object; - final Mesh.Mode mode = mesh.getMode(); - - final int id = mesh.getId(); - final int instanceCount = mesh.getInstanceCount(); - final int vertexCount = mesh.getVertexCount(); - final int numLodLevels = mesh.getNumLodLevels(); - final int triangleCount = mesh.getTriangleCount(); - - final DefaultSinglePropertyControl idControl = - new DefaultSinglePropertyControl<>(id, Messages.MODEL_PROPERTY_ID, changeConsumer); - - idControl.setSyncHandler(Mesh::getId); - idControl.setToStringFunction(value -> Integer.toString(value)); - idControl.setEditObject(mesh); - - final DefaultSinglePropertyControl instanceCountControl = - new DefaultSinglePropertyControl<>(instanceCount, Messages.MODEL_PROPERTY_INSTANCE_COUNT, changeConsumer); - - instanceCountControl.setSyncHandler(Mesh::getInstanceCount); - instanceCountControl.setToStringFunction(value -> Integer.toString(value)); - instanceCountControl.setEditObject(mesh); - - final DefaultSinglePropertyControl vertexCountControl = - new DefaultSinglePropertyControl<>(vertexCount, Messages.MODEL_PROPERTY_VERTEX_COUNT, changeConsumer); - - vertexCountControl.setSyncHandler(Mesh::getVertexCount); - vertexCountControl.setToStringFunction(value -> Integer.toString(value)); - vertexCountControl.setEditObject(mesh); - - final DefaultSinglePropertyControl triangleCountControl = - new DefaultSinglePropertyControl<>(triangleCount, Messages.MODEL_PROPERTY_TRIANGLE_COUNT, changeConsumer); - - triangleCountControl.setSyncHandler(Mesh::getTriangleCount); - triangleCountControl.setToStringFunction(value -> Integer.toString(value)); - triangleCountControl.setEditObject(mesh); - - final DefaultSinglePropertyControl numLodLevelsControl = - new DefaultSinglePropertyControl<>(numLodLevels, Messages.MODEL_PROPERTY_NUM_LOD_LEVELS, changeConsumer); - - numLodLevelsControl.setSyncHandler(Mesh::getNumLodLevels); - numLodLevelsControl.setToStringFunction(value -> Integer.toString(value)); - numLodLevelsControl.setEditObject(mesh); - - final EnumPropertyControl modeControl = - new EnumPropertyControl<>(mode, Messages.MODEL_PROPERTY_MODE, changeConsumer, MODES); - modeControl.setApplyHandler(Mesh::setMode); - modeControl.setSyncHandler(Mesh::getMode); - modeControl.setEditObject(mesh); - - FXUtils.addToPane(idControl, container); - FXUtils.addToPane(instanceCountControl, container); - FXUtils.addToPane(vertexCountControl, container); - FXUtils.addToPane(triangleCountControl, container); - FXUtils.addToPane(numLodLevelsControl, container); - FXUtils.addToPane(modeControl, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java deleted file mode 100644 index 11dad8cd..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/ParticleInfluencerPropertyBuilder.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.effect.influencers.EmptyParticleInfluencer; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.jme3.effect.influencers.RadialParticleInfluencer; -import com.jme3.math.Vector3f; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.BooleanPropertyControl; -import com.ss.editor.ui.control.property.impl.FloatPropertyControl; -import com.ss.editor.ui.control.property.impl.Vector3fPropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for {@link ParticleInfluencer}. - * - * @author JavaSaBr - */ -public class ParticleInfluencerPropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final PropertyBuilder INSTANCE = new ParticleInfluencerPropertyBuilder(); - - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private ParticleInfluencerPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, - @NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer) { - - if (!(object instanceof ParticleInfluencer)) return; - - final ParticleInfluencer influencer = (ParticleInfluencer) object; - final Vector3f initialVelocity = influencer.getInitialVelocity(); - - final float velocityVariation = influencer.getVelocityVariation(); - - final Vector3fPropertyControl initialVelocityControl = - new Vector3fPropertyControl<>(initialVelocity, Messages.MODEL_PROPERTY_INITIAL_VELOCITY, changeConsumer); - - initialVelocityControl.setSyncHandler(ParticleInfluencer::getInitialVelocity); - initialVelocityControl.setApplyHandler(ParticleInfluencer::setInitialVelocity); - initialVelocityControl.setEditObject(influencer); - - FXUtils.addToPane(initialVelocityControl, container); - - if (object instanceof RadialParticleInfluencer) { - createControls(container, changeConsumer, (RadialParticleInfluencer) object); - } else { - buildSplitLine(initialVelocityControl); - } - - if (influencer instanceof EmptyParticleInfluencer) { - initialVelocityControl.setDisable(true); - } - - final FloatPropertyControl velocityVariationControl = - new FloatPropertyControl<>(velocityVariation, Messages.MODEL_PROPERTY_VELOCITY_VARIATION, changeConsumer); - - velocityVariationControl.setSyncHandler(ParticleInfluencer::getVelocityVariation); - velocityVariationControl.setApplyHandler(ParticleInfluencer::setVelocityVariation); - velocityVariationControl.setEditObject(influencer); - - FXUtils.addToPane(velocityVariationControl, container); - } - - /** - * Create controls. - * - * @param container the container. - * @param changeConsumer the change consumer. - * @param influencer the influencer. - */ - @FxThread - private void createControls(@NotNull final VBox container, final @NotNull ModelChangeConsumer changeConsumer, - @NotNull final RadialParticleInfluencer influencer) { - - final Vector3f origin = influencer.getOrigin(); - final float radialVelocity = influencer.getRadialVelocity(); - final boolean horizontal = influencer.isHorizontal(); - - final FloatPropertyControl radialVelocityControl = - new FloatPropertyControl<>(radialVelocity, Messages.MODEL_PROPERTY_RADIAL_VELOCITY, changeConsumer); - - radialVelocityControl.setSyncHandler(RadialParticleInfluencer::getRadialVelocity); - radialVelocityControl.setApplyHandler(RadialParticleInfluencer::setRadialVelocity); - radialVelocityControl.setEditObject(influencer); - - final BooleanPropertyControl horizontalControl = - new BooleanPropertyControl<>(horizontal, Messages.MODEL_PROPERTY_IS_HORIZONTAL, changeConsumer); - - horizontalControl.setSyncHandler(RadialParticleInfluencer::isHorizontal); - horizontalControl.setApplyHandler(RadialParticleInfluencer::setHorizontal); - horizontalControl.setEditObject(influencer); - - final Vector3fPropertyControl originControl = - new Vector3fPropertyControl<>(origin, Messages.MODEL_PROPERTY_ORIGIN, changeConsumer); - - originControl.setSyncHandler(RadialParticleInfluencer::getOrigin); - originControl.setApplyHandler(RadialParticleInfluencer::setOrigin); - originControl.setEditObject(influencer); - - FXUtils.addToPane(originControl, container); - buildSplitLine(container); - FXUtils.addToPane(radialVelocityControl, container); - FXUtils.addToPane(horizontalControl, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/PrimitivePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/PrimitivePropertyBuilder.java deleted file mode 100644 index b2273a5f..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/PrimitivePropertyBuilder.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.jme3.math.Vector3f; -import com.jme3.scene.VertexBuffer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.builder.PropertyBuilder; -import com.ss.editor.ui.control.property.impl.DefaultSinglePropertyControl; -import com.ss.editor.ui.control.property.impl.Vector3fPropertyControl; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.Buffer; - -/** - * The implementation of the {@link PropertyBuilder} to build property controls for primitive objects objects. - * - * @author JavaSaBr - */ -public class PrimitivePropertyBuilder extends AbstractPropertyBuilder { - - @NotNull - private static final PropertyBuilder INSTANCE = new PrimitivePropertyBuilder(); - - /** - * Gets the instance. - * - * @return the single instance. - */ - @FromAnyThread - public static @NotNull PropertyBuilder getInstance() { - return INSTANCE; - } - - private PrimitivePropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - protected void buildForImpl(@NotNull final Object object, @Nullable final Object parent, - @NotNull final VBox container, @NotNull final ModelChangeConsumer changeConsumer) { - - if (object instanceof Vector3f) { - - final Vector3f position = (Vector3f) object; - final Vector3f value = position.clone(); - - final Vector3fPropertyControl control = - new Vector3fPropertyControl<>(value, Messages.MODEL_PROPERTY_VALUE, changeConsumer); - control.setApplyHandler(Vector3f::set); - control.setSyncHandler(Vector3f::clone); - control.setEditObject(position); - - FXUtils.addToPane(control, container); - - } else if (object instanceof VertexBuffer) { - - final VertexBuffer vertexBuffer = (VertexBuffer) object; - final Buffer data = vertexBuffer.getData(); - if (data == null) return; - - final VertexBuffer.Type bufferType = vertexBuffer.getBufferType(); - final VertexBuffer.Format format = vertexBuffer.getFormat(); - final VertexBuffer.Usage usage = vertexBuffer.getUsage(); - - final long uniqueId = vertexBuffer.getUniqueId(); - - final int baseInstanceCount = vertexBuffer.getBaseInstanceCount(); - final int instanceSpan = vertexBuffer.getInstanceSpan(); - final int numComponents = vertexBuffer.getNumComponents(); - final int numElements = vertexBuffer.getNumElements(); - final int offset = vertexBuffer.getOffset(); - final int stride = vertexBuffer.getStride(); - - final DefaultSinglePropertyControl bufferTypeControl = - new DefaultSinglePropertyControl<>(bufferType, Messages.MODEL_PROPERTY_TYPE, changeConsumer); - - bufferTypeControl.setSyncHandler(VertexBuffer::getBufferType); - bufferTypeControl.setToStringFunction(Enum::name); - bufferTypeControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl formatControl = - new DefaultSinglePropertyControl<>(format, Messages.MODEL_PROPERTY_FORMAT, changeConsumer); - - formatControl.setSyncHandler(VertexBuffer::getFormat); - formatControl.setToStringFunction(Enum::name); - formatControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl usageControl = - new DefaultSinglePropertyControl<>(usage, Messages.MODEL_PROPERTY_USAGE, changeConsumer); - - usageControl.setSyncHandler(VertexBuffer::getUsage); - usageControl.setToStringFunction(Enum::name); - usageControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl uniqIdControl = - new DefaultSinglePropertyControl<>(uniqueId, Messages.MODEL_PROPERTY_UNIQ_ID, changeConsumer); - - uniqIdControl.setSyncHandler(VertexBuffer::getUniqueId); - uniqIdControl.setToStringFunction(value -> Long.toString(value)); - uniqIdControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl baseInstanceCountControl = - new DefaultSinglePropertyControl<>(baseInstanceCount, Messages.MODEL_PROPERTY_BASE_INSTANCE_COUNT, changeConsumer); - - baseInstanceCountControl.setSyncHandler(VertexBuffer::getBaseInstanceCount); - baseInstanceCountControl.setToStringFunction(value -> Integer.toString(value)); - baseInstanceCountControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl instanceSpanControl = - new DefaultSinglePropertyControl<>(instanceSpan, Messages.MODEL_PROPERTY_INSTANCE_SPAN, changeConsumer); - - instanceSpanControl.setSyncHandler(VertexBuffer::getBaseInstanceCount); - instanceSpanControl.setToStringFunction(value -> Integer.toString(value)); - instanceSpanControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl numComponentsControl = - new DefaultSinglePropertyControl<>(numComponents, Messages.MODEL_PROPERTY_NUM_COMPONENTS, changeConsumer); - - numComponentsControl.setSyncHandler(VertexBuffer::getNumComponents); - numComponentsControl.setToStringFunction(value -> Integer.toString(value)); - numComponentsControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl numElementsControl = - new DefaultSinglePropertyControl<>(numElements, Messages.MODEL_PROPERTY_NUM_ELEMENTS, changeConsumer); - - numElementsControl.setSyncHandler(VertexBuffer::getNumElements); - numElementsControl.setToStringFunction(value -> Integer.toString(value)); - numElementsControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl offsetControl = - new DefaultSinglePropertyControl<>(offset, Messages.MODEL_PROPERTY_OFFSET, changeConsumer); - - offsetControl.setSyncHandler(VertexBuffer::getOffset); - offsetControl.setToStringFunction(value -> Integer.toString(value)); - offsetControl.setEditObject(vertexBuffer); - - final DefaultSinglePropertyControl strideControl = - new DefaultSinglePropertyControl<>(stride, Messages.MODEL_PROPERTY_STRIDE, changeConsumer); - - strideControl.setSyncHandler(VertexBuffer::getStride); - strideControl.setToStringFunction(value -> Integer.toString(value)); - strideControl.setEditObject(vertexBuffer); - - FXUtils.addToPane(bufferTypeControl, container); - FXUtils.addToPane(formatControl, container); - FXUtils.addToPane(usageControl, container); - FXUtils.addToPane(uniqIdControl, container); - FXUtils.addToPane(baseInstanceCountControl, container); - FXUtils.addToPane(instanceSpanControl, container); - FXUtils.addToPane(numComponentsControl, container); - FXUtils.addToPane(numElementsControl, container); - FXUtils.addToPane(offsetControl, container); - FXUtils.addToPane(strideControl, container); - - } else if (object instanceof Buffer) { - - final Buffer buffer = (Buffer) object; - final int capacity = buffer.capacity(); - - final DefaultSinglePropertyControl capacityControl = - new DefaultSinglePropertyControl<>(capacity, Messages.MODEL_PROPERTY_CAPACITY, changeConsumer); - - capacityControl.setSyncHandler(Buffer::capacity); - capacityControl.setToStringFunction(integer -> Integer.toString(integer)); - capacityControl.setEditObject(buffer); - - FXUtils.addToPane(capacityControl, container); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneAppStatePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneAppStatePropertyBuilder.java deleted file mode 100644 index 8a8f53e7..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneAppStatePropertyBuilder.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.extension.scene.app.state.EditableSceneAppState; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The property builder to build property controls of editable scene app states. - * - * @author JavaSaBr - */ -public class SceneAppStatePropertyBuilder extends EditableModelObjectPropertyBuilder { - - @NotNull - private static final SceneAppStatePropertyBuilder INSTANCE = new SceneAppStatePropertyBuilder(); - - @FromAnyThread - public static @NotNull SceneAppStatePropertyBuilder getInstance() { - return INSTANCE; - } - - protected SceneAppStatePropertyBuilder() { - super(SceneChangeConsumer.class); - } - - @Override - @FxThread - protected @Nullable List> getProperties(@NotNull final Object object) { - if (object instanceof EditableSceneAppState) { - return ((EditableSceneAppState) object).getEditableProperties(); - } else { - return null; - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneFilterPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneFilterPropertyBuilder.java deleted file mode 100644 index 0c2391e1..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SceneFilterPropertyBuilder.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ss.editor.ui.control.property.builder.impl; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.property.EditableProperty; -import com.ss.editor.extension.scene.filter.EditableSceneFilter; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The property builder to build property controls of editable scene app states. - * - * @author JavaSaBr - */ -public class SceneFilterPropertyBuilder extends EditableModelObjectPropertyBuilder { - - @NotNull - private static final SceneFilterPropertyBuilder INSTANCE = new SceneFilterPropertyBuilder(); - - @FromAnyThread - public static @NotNull SceneFilterPropertyBuilder getInstance() { - return INSTANCE; - } - - protected SceneFilterPropertyBuilder() { - super(ModelChangeConsumer.class); - } - - @Override - @FxThread - protected @Nullable List> getProperties(@NotNull final Object object) { - if (object instanceof EditableSceneFilter) { - return ((EditableSceneFilter) object).getEditableProperties(); - } else { - return null; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java deleted file mode 100644 index 87c141c6..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.FileExtensions.AUDIO_EXTENSIONS; -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioNode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.event.impl.RequestedOpenFileEvent; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FxUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.event.ActionEvent; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.input.DragEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * The implementation of the {@link PropertyControl} to edit the {@link AudioData}. - * - * @param the type of a change consumer. - * @author JavaSaBr - */ -public class AudioKeyPropertyControl extends PropertyControl { - - @NotNull - private static final String NO_AUDIO = Messages.AUDIO_KEY_PROPERTY_CONTROL_NO_AUDIO; - - /** - * The label with name of the audio key. - */ - @Nullable - private Label audioKeyLabel; - - public AudioKeyPropertyControl( - @Nullable AudioKey element, - @NotNull String paramName, - @NotNull C changeConsumer - ) { - super(element, paramName, changeConsumer); - setOnDragOver(this::handleDragOverEvent); - setOnDragDropped(this::handleDragDroppedEvent); - setOnDragExited(this::handleDragExitedEvent); - } - - /** - * Handle drag exited events. - * - * @param dragEvent the drag exited event. - */ - private void handleDragExitedEvent(@NotNull DragEvent dragEvent) { - } - - /** - * Handle dropped events. - * - * @param dragEvent the dropped event. - */ - private void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { - UiUtils.handleDroppedFile(dragEvent, AUDIO_EXTENSIONS, this, AudioKeyPropertyControl::addAudioData); - } - - /** - * Handle drag over events. - * - * @param dragEvent the drag over events. - */ - private void handleDragOverEvent(@NotNull DragEvent dragEvent) { - UiUtils.acceptIfHasFile(dragEvent, AUDIO_EXTENSIONS); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - audioKeyLabel = new Label(NO_AUDIO); - - var changeButton = new Button(); - changeButton.setGraphic(new ImageView(Icons.ADD_16)); - changeButton.setOnAction(this::processChange); - - var openButton = new Button(); - openButton.setGraphic(new ImageView(Icons.EDIT_16)); - openButton.setOnAction(this::openAudio); - openButton.disableProperty() - .bind(audioKeyLabel.textProperty().isEqualTo(NO_AUDIO)); - - audioKeyLabel.prefWidthProperty() - .bind(widthProperty() - .subtract(changeButton.widthProperty()) - .subtract(openButton.widthProperty())); - - FxUtils.addClass(container, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) - .addClass(audioKeyLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) - .addClass(changeButton, openButton, - CssClasses.FLAT_BUTTON, - CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); - - FxUtils.addChild(container, - audioKeyLabel, changeButton, openButton); - - DynamicIconSupport.addSupport(changeButton, openButton); - } - - /** - * Show dialog for choosing another audio key. - * - * @param event the action event. - */ - @FxThread - protected void processChange(@Nullable ActionEvent event) { - UiUtils.openFileAssetDialog(this::addAudioData, AUDIO_EXTENSIONS, DEFAULT_ACTION_TESTER); - } - - /** - * Add the new audio data. - * - * @param file the audio file. - */ - @FxThread - private void addAudioData(@NotNull Path file) { - - var assetFile = notNull(getAssetFile(file)); - var audioKey = new AudioKey(toAssetPath(assetFile)); - - changed(audioKey, getPropertyValue()); - setIgnoreListener(true); - try { - reload(); - } finally { - setIgnoreListener(false); - } - } - - /** - * Open this audio data in the audio viewer. - * - * @param event the action event. - */ - @FxThread - protected void openAudio(@Nullable ActionEvent event) { - - var element = getPropertyValue(); - if (element == null) { - return; - } - - var assetPath = element.getName(); - if (StringUtils.isEmpty(assetPath)) { - return; - } - - var assetFile = Paths.get(assetPath); - var realFile = notNull(getRealFile(assetFile)); - if (!Files.exists(realFile)) { - return; - } - - FX_EVENT_MANAGER.notify(new RequestedOpenFileEvent(realFile)); - } - - /** - * Get the audio key label. - * - * @return the audio key label. - */ - @FxThread - private @NotNull Label getAudioKeyLabel() { - return notNull(audioKeyLabel); - } - - @Override - @FxThread - protected void reload() { - getAudioKeyLabel().setText(getKeyLabel(getPropertyValue())); - } - - private @NotNull String getKeyLabel(@Nullable AudioKey assetKey) { - return EditorUtil.isEmpty(assetKey) ? NO_AUDIO : assetKey.getName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java deleted file mode 100644 index ae72f986..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.lang.Boolean.TRUE; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.CheckBox; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -/** - * The implementation of the {@link PropertyControl} to change boolean values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class BooleanPropertyControl extends PropertyControl { - - /** - * The field with current value. - */ - @Nullable - private CheckBox checkBox; - - public BooleanPropertyControl( - @Nullable Boolean propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public BooleanPropertyControl( - @Nullable Boolean propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - checkBox = new CheckBox(); - checkBox.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onSelectedChange(checkBox, this::updateValue); - - FxUtils.addClass(checkBox, - CssClasses.PROPERTY_CONTROL_CHECK_BOX); - - FxUtils.addChild(container, checkBox); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getCheckBox(), - widthProperty().multiply(controlWidthPercent)); - } - - /** - * Disable the offset of checkbox control. - */ - @FxThread - public void disableCheckboxOffset() { - FxUtils.resetPrefWidth(getCheckBox()); - FxUtils.resetMinMaxWidth(getPropertyNameLabel()) - .prefWidthProperty().bind(widthProperty()); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the field with current value. - * - * @return the field with current value. - */ - @FxThread - private @NotNull CheckBox getCheckBox() { - return notNull(checkBox); - } - - @Override - @FxThread - protected void reload() { - getCheckBox().setSelected(TRUE.equals(getPropertyValue())); - } - - @FxThread - @Override - public boolean isDirty() { - return !Objects.equals(getPropertyValue(), getCheckBox().isSelected()); - } - - /** - * Update the value. - */ - @FxThread - private void updateValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - protected void apply() { - super.apply(); - changed(getCheckBox().isSelected(), getPropertyValue()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java deleted file mode 100644 index 0389b066..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.ColorRGBA; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ColorPicker; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit a color values. - * - * @param the change - * @param the type parameter - * @author JavaSaBr - */ -public class ColorPropertyControl extends PropertyControl { - - /** - * The color picker. - */ - @Nullable - private ColorPicker colorPicker; - - public ColorPropertyControl( - @Nullable ColorRGBA propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - colorPicker = new ColorPicker(); - colorPicker.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onColorChange(colorPicker, this::updateValue); - - FxUtils.addClass(colorPicker, - CssClasses.PROPERTY_CONTROL_COLOR_PICKER); - - FxUtils.addChild(container, colorPicker); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getColorPicker(), - widthProperty().multiply(controlWidthPercent)); - } - - @Override - @FxThread - protected void setPropertyValue(@Nullable ColorRGBA color) { - super.setPropertyValue(color == null ? null : color.clone()); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the color picker. - * - * @return the color picker. - */ - @FxThread - private @NotNull ColorPicker getColorPicker() { - return notNull(colorPicker); - } - - @Override - @FxThread - protected void reload() { - getColorPicker().setValue(UiUtils.from(getPropertyValue())); - } - - /** - * Updating value. - */ - @FxThread - private void updateValue() { - - if (isIgnoreListener()) { - return; - } - - var colorPicker = getColorPicker(); - var newColor = UiUtils.from(colorPicker.getValue()); - var oldValue = getPropertyValue(); - - changed(newColor, oldValue == null ? null : oldValue.clone()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java deleted file mode 100644 index b919d17a..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Function; - -/** - * The default implementation of the property control. - * - * @param the change consumer's type. - * @param the edited object's type. - * @param the edited property's type. - * @author JavaSaBr - */ -public class DefaultPropertyControl extends PropertyControl { - - /** - * The label with value of the property. - */ - @Nullable - protected Label propertyValueLabel; - - /** - * The string function. - */ - @Nullable - private Function toStringFunction; - - public DefaultPropertyControl( - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - /** - * Set the string function. - * - * @param toStringFunction the string function. - */ - @FromAnyThread - public void setToStringFunction(@Nullable Function toStringFunction) { - this.toStringFunction = toStringFunction; - } - - /** - * Get the string function. - * - * @return the string function. - */ - @FromAnyThread - private @Nullable Function getToStringFunction() { - return toStringFunction; - } - - /** - * Get the label with value of the property. - * - * @return the label with value of the property. - */ - protected @NotNull Label getPropertyValueLabel() { - return notNull(propertyValueLabel); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - propertyValueLabel = new Label(); - propertyValueLabel.prefWidthProperty() - .bind(container.widthProperty()); - - FxUtils.addClass(propertyValueLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_LABEL_VALUE, - CssClasses.TEXT_INPUT_CONTAINER); - - FxUtils.addChild(container, propertyValueLabel); - } - - @Override - @FxThread - public void reload() { - super.reload(); - - var function = getToStringFunction(); - var propertyValueLabel = getPropertyValueLabel(); - propertyValueLabel.setText(function == null ? String.valueOf(getPropertyValue()) : - function.apply(getPropertyValue())); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java deleted file mode 100644 index 9cf091b9..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The default implementation of the property control. - * - * @param the change consumer's type. - * @param the edited object's type. - * @param the edited property's type. - * @author JavaSaBr - */ -public class DefaultSinglePropertyControl extends DefaultPropertyControl { - - public DefaultSinglePropertyControl( - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - getPropertyValueLabel().prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java deleted file mode 100644 index f9e626a5..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.jme3.light.Light; -import com.jme3.math.Vector3f; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link Vector3fPropertyControl} to edit direction's vector of the {@link Light}. - * - * @param the light's type. - * @author JavaSaBr - */ -public class DirectionLightPropertyControl extends Vector3fPropertyControl { - - public DirectionLightPropertyControl( - @NotNull Vector3f element, - @NotNull String paramName, - @NotNull ModelChangeConsumer modelChangeConsumer - ) { - super(element, paramName, modelChangeConsumer); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/ElementPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/ElementPropertyControl.java deleted file mode 100644 index de622f0b..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/ElementPropertyControl.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit an elements from scene. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @param the type of an editing property. - * @author JavaSaBr - */ -public class ElementPropertyControl extends PropertyControl { - - /** - * The constant NO_ELEMENT. - */ - @NotNull - protected static final String NO_ELEMENT = Messages.ABSTRACT_ELEMENT_PROPERTY_CONTROL_NO_ELEMENT; - - /** - * The type of an element. - */ - @NotNull - protected final Class type; - - /** - * The label with name of the element. - */ - @Nullable - private Label elementLabel; - - public ElementPropertyControl( - @NotNull Class type, - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - this.type = type; - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - elementLabel = new Label(NO_ELEMENT); - elementLabel.prefWidthProperty() - .bind(container.widthProperty()); - - var changeButton = new Button(); - changeButton.setGraphic(new ImageView(Icons.ADD_16)); - changeButton.setOnAction(event -> addElement()); - - var editButton = new Button(); - editButton.setGraphic(new ImageView(Icons.REMOVE_12)); - editButton.setOnAction(event -> removeElement()); - editButton.disableProperty() - .bind(elementLabel.textProperty().isEqualTo(NO_ELEMENT)); - - FxUtils.addClass(container, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) - .addClass(elementLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) - .addClass(changeButton, editButton, - CssClasses.FLAT_BUTTON, - CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); - - FxUtils.addChild(container, elementLabel, changeButton, editButton); - - DynamicIconSupport.addSupport(changeButton, editButton); - } - - /** - * Show a dialog to choose an element. - */ - @FxThread - protected void addElement() { - } - - /** - * Remove the current element. - */ - @FxThread - protected void removeElement() { - changed(null, getPropertyValue()); - } - - /** - * Get the element label. - * - * @return the element label. - */ - @FxThread - protected @NotNull Label getElementLabel() { - return notNull(elementLabel); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java deleted file mode 100644 index 85088ccb..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.util.EditorUtil.getAvailableValues; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ComboBox; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit {@link Enum} values. - * - * @param the type of a {@link ChangeConsumer} - * @param the type of an editing object. - * @param the type of editing enum. - * @author JavaSaBr - */ -public class EnumPropertyControl> extends PropertyControl { - - /** - * The list of available options of the {@link Enum} value. - */ - @Nullable - private ComboBox enumComboBox; - - public EnumPropertyControl( - @Nullable E propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @NotNull E[] availableValues - ) { - super(propertyValue, propertyName, changeConsumer); - getEnumComboBox().getItems() - .addAll(availableValues); - } - - public EnumPropertyControl( - @NotNull E propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - this(propertyValue, propertyName, changeConsumer, getAvailableValues(propertyValue)); - } - - public EnumPropertyControl( - @Nullable E propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @NotNull E[] availableValues, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - getEnumComboBox().getItems() - .addAll(availableValues); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - enumComboBox = new ComboBox<>(); - enumComboBox.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onSelectedItemChange(enumComboBox, this::change); - - FxUtils.addClass(enumComboBox, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, enumComboBox); - } - - /** - * Get the list of available options of the {@link Enum} value. - * - * @return the list of available options of the {@link Enum} value. - */ - @FxThread - private @NotNull ComboBox getEnumComboBox() { - return notNull(enumComboBox); - } - - /** - * Update selected {@link Enum} value. - */ - @FxThread - private void change() { - - if (isIgnoreListener()) { - return; - } - - var enumComboBox = getEnumComboBox(); - var selectionModel = enumComboBox.getSelectionModel(); - var newValue = selectionModel.getSelectedItem(); - - changed(newValue, getPropertyValue()); - } - - @Override - @FxThread - protected void reload() { - getEnumComboBox().getSelectionModel() - .select(getPropertyValue()); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/FilterElementModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/FilterElementModelPropertyControl.java deleted file mode 100644 index 812e22b5..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/FilterElementModelPropertyControl.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.jme3.post.Filter; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.dialog.scene.selector.FilterSceneSelectorDialog; -import com.ss.editor.ui.dialog.scene.selector.SceneSelectorDialog; -import com.ss.rlib.common.util.StringUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link SceneElementPropertyControl} to edit light from a scene. - * - * @param the edited object's type. - * @author JavaSaBr - */ -public class FilterElementModelPropertyControl extends SceneElementPropertyControl { - - public FilterElementModelPropertyControl( - @Nullable Filter propertyValue, - @NotNull String propertyName, - @NotNull SceneChangeConsumer changeConsumer - ) { - super(Filter.class, propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected @NotNull SceneSelectorDialog createSceneSelectorDialog() { - return new FilterSceneSelectorDialog(getChangeConsumer().getCurrentModel(), this::addElement); - } - - @Override - @FxThread - protected void reload() { - - var filter = getPropertyValue(); - - String name = filter == null ? null : filter.getName(); - name = StringUtils.isEmpty(name) && filter != null ? filter.getClass().getSimpleName() : name; - - getElementLabel().setText(StringUtils.ifEmpty(name, NO_ELEMENT)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java deleted file mode 100644 index c40b9d3e..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.StringUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; - -/** - * The implementation of the {@link PropertyControl} to edit float array values. - * - * @param the change consumer's type. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class FloatArrayPropertyControl - extends StringBasedArrayPropertyControl { - - public FloatArrayPropertyControl( - @Nullable float[] propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public FloatArrayPropertyControl( - @Nullable float[] propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - protected void reload() { - - var element = getPropertyValue(); - var valueField = getValueField(); - var caretPosition = valueField.getCaretPosition(); - - if (element == null) { - valueField.setText(StringUtils.EMPTY); - } else { - valueField.setText(ArrayUtils.toString(element, " ", false, false)); - } - - valueField.positionCaret(caretPosition); - } - - @Override - @FxThread - public boolean isDirty() { - return !Arrays.equals(getCurrentValue(), getPropertyValue()); - } - - @Override - @FxThread - protected @Nullable float[] getCurrentValue() { - - var textValue = getValueField().getText(); - - float[] newValue = null; - - if (!StringUtils.isEmpty(textValue)) { - - var splitter = textValue.contains(" ") ? " " : ","; - var split = textValue.split(splitter); - - newValue = new float[split.length]; - - for (var i = 0; i < split.length; i++) { - try { - newValue[i] = Float.parseFloat(split[i]); - } catch (NumberFormatException e) { - LOGGER.warning(this, e); - newValue = getPropertyValue(); - break; - } - } - } - - return newValue; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java deleted file mode 100644 index 4c1cae91..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.NumberUtils.zeroIfNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -/** - * The implementation of the {@link PropertyControl} to edit float values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class FloatPropertyControl extends PropertyControl { - - /** - * The filed with current value. - */ - @Nullable - private FloatTextField valueField; - - public FloatPropertyControl( - @Nullable Float propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public FloatPropertyControl( - @Nullable Float propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getValueField(), - widthProperty().multiply(controlWidthPercent)); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - valueField = new FloatTextField(); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onValueChange(valueField, this::updateValue); - FxControlUtils.onFocusChange(valueField, this::applyOnLostFocus); - - FxUtils.addClass(valueField, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, valueField); - } - - /** - * Set the scroll power. - * - * @param scrollPower the scroll power. - */ - @FxThread - public void setScrollPower(float scrollPower) { - getValueField().setScrollPower(scrollPower); - } - - /** - * Get the scroll power. - * - * @return the scroll power. - */ - @FxThread - public float getScrollPower() { - return getValueField().getScrollPower(); - } - - /** - * Set the value limits for this field. - * - * @param min the min value. - * @param max the max value. - */ - @FxThread - public void setMinMax(float min, float max) { - getValueField().setMinMax(min, max); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the filed with current value. - * - * @return the filed with current value. - */ - @FxThread - private @NotNull FloatTextField getValueField() { - return notNull(valueField); - } - - @Override - @FxThread - protected void reload() { - var valueField = getValueField(); - var caretPosition = valueField.getCaretPosition(); - valueField.setValue(zeroIfNull(getPropertyValue())); - valueField.positionCaret(caretPosition); - } - - @Override - @FxThread - public boolean isDirty() { - return !Objects.equals(getValueField().getValue(), getPropertyValue()); - } - - /** - * Update the value. - */ - @FxThread - private void updateValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - changed(getValueField().getValue(), getPropertyValue()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java deleted file mode 100644 index 5e2ea535..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.control.TextField; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; - -/** - * The implementation of the {@link PropertyControl} to edit int array values. - * - * @param the change consumer's type. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class IntArrayPropertyControl extends StringBasedArrayPropertyControl { - - /** - * The filed with current value. - */ - @Nullable - private TextField valueField; - - public IntArrayPropertyControl( - @Nullable int[] propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public IntArrayPropertyControl( - @Nullable int[] propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - protected void reload() { - - var element = getPropertyValue(); - - var valueField = getValueField(); - var caretPosition = valueField.getCaretPosition(); - - if (element == null) { - valueField.setText(StringUtils.EMPTY); - } else { - valueField.setText(ArrayUtils.toString(element, " ", false, false)); - } - - valueField.positionCaret(caretPosition); - } - - @Override - @FxThread - public boolean isDirty() { - return !Arrays.equals(getCurrentValue(), getPropertyValue()); - } - - @Override - @FxThread - protected @Nullable int[] getCurrentValue() { - - var textValue = getValueField().getText(); - - int[] newValue = null; - - if (!StringUtils.isEmpty(textValue)) { - - var splitter = textValue.contains(" ") ? " " : ","; - var split = textValue.split(splitter); - - newValue = new int[split.length]; - - for (var i = 0; i < split.length; i++) { - try { - newValue[i] = Integer.parseInt(split[i]); - } catch (NumberFormatException e) { - LOGGER.warning(this, e); - newValue = getPropertyValue(); - break; - } - } - } - - return newValue; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java deleted file mode 100644 index 8d17065b..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.NumberUtils.zeroIfNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.control.input.IntegerTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -/** - * The implementation of the {@link PropertyControl} to edit integer values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class IntegerPropertyControl extends PropertyControl { - - /** - * The filed with current value. - */ - @Nullable - private IntegerTextField valueField; - - public IntegerPropertyControl( - @Nullable Integer propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getValueField(), - widthProperty().multiply(controlWidthPercent)); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - valueField = new IntegerTextField(); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onValueChange(valueField, this::updateValue); - FxControlUtils.onFocusChange(valueField, this::applyOnLostFocus); - - FxUtils.addClass(valueField, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, valueField); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the filed with current value. - * - * @return the filed with current value. - */ - @FxThread - private @NotNull IntegerTextField getValueField() { - return notNull(valueField); - } - - /** - * Set value limits for this field. - * - * @param min the min value. - * @param max the max value. - */ - @FxThread - public void setMinMax(int min, int max) { - getValueField().setMinMax(min, max); - } - - /** - * Set the scroll power. - * - * @param scrollPower the scroll power. - */ - @FxThread - public void setScrollPower(int scrollPower) { - getValueField().setScrollPower(scrollPower); - } - - /** - * Get the scroll power. - * - * @return the scroll power. - */ - @FxThread - public int getScrollPower() { - return (int) getValueField().getScrollPower(); - } - - @Override - @FxThread - protected void reload() { - var valueField = getValueField(); - var caretPosition = valueField.getCaretPosition(); - valueField.setValue(zeroIfNull(getPropertyValue())); - valueField.positionCaret(caretPosition); - } - - @Override - @FxThread - public boolean isDirty() { - return !Objects.equals(getValueField().getValue(), getPropertyValue()); - } - - /** - * Update the value. - */ - @FxThread - private void updateValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - changed(getValueField().getValue(), getPropertyValue()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/LayerModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/LayerModelPropertyControl.java deleted file mode 100644 index 478f8c5a..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/LayerModelPropertyControl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.ifNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.ComboBox; -import javafx.scene.control.ListCell; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit layers. - * - * @param the type of an editing object. - * @author JavaSaBr - */ -public class LayerModelPropertyControl extends PropertyControl { - - @NotNull - private class LayerCell extends ListCell { - - @Override - protected void updateItem(@Nullable SceneLayer layer, boolean empty) { - super.updateItem(layer, empty); - - if (layer == null || layer == SceneLayer.NO_LAYER) { - setText(Messages.LAYER_PROPERTY_CONTROL_NO_LAYER); - return; - } - - setText(layer.getName()); - } - } - - /** - * The layers combo box. - */ - @Nullable - private ComboBox layerComboBox; - - public LayerModelPropertyControl( - @Nullable SceneLayer layer, - @NotNull String propertyName, - @NotNull SceneChangeConsumer changeConsumer - ) { - super(ifNull(layer, SceneLayer.NO_LAYER), propertyName, changeConsumer); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - layerComboBox = new ComboBox<>(); - layerComboBox.setCellFactory(param -> new LayerCell()); - layerComboBox.setButtonCell(new LayerCell()); - layerComboBox.setEditable(false); - layerComboBox.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onSelectedItemChange(layerComboBox, this::updateLevel); - - FxUtils.addClass(layerComboBox, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, layerComboBox); - } - - @FxThread - private void updateLevel(@Nullable SceneLayer layer) { - if (isIgnoreListener()) return; - changed(layer, getPropertyValue()); - } - - /** - * Get the layers combo box. - * - * @return the layers combo box. - */ - @FxThread - protected @NotNull ComboBox getLayerComboBox() { - return notNull(layerComboBox); - } - - @Override - @FxThread - protected void reload() { - - var changeConsumer = (SceneChangeConsumer) getChangeConsumer(); - var currentModel = changeConsumer.getCurrentModel(); - var sceneLayer = getPropertyValue(); - - var levelComboBox = getLayerComboBox(); - var items = levelComboBox.getItems(); - items.clear(); - items.add(SceneLayer.NO_LAYER); - items.addAll(currentModel.getLayers()); - - levelComboBox.getSelectionModel() - .select(sceneLayer == null ? SceneLayer.NO_LAYER : sceneLayer); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/LightElementModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/LightElementModelPropertyControl.java deleted file mode 100644 index 4068fe5d..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/LightElementModelPropertyControl.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.jme3.light.Light; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.dialog.node.selector.LightSelectorDialog; -import com.ss.editor.ui.dialog.node.selector.NodeSelectorDialog; -import com.ss.rlib.common.util.StringUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link ElementModelPropertyControl} to edit light from a scene. - * - * @param the edited object's type. - * @author JavaSaBr - */ -public class LightElementModelPropertyControl extends ElementModelPropertyControl { - - public LightElementModelPropertyControl( - @NotNull Class type, - @Nullable L propertyValue, - @NotNull String propertyName, - @NotNull ModelChangeConsumer changeConsumer - ) { - super(type, propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected @NotNull NodeSelectorDialog createNodeSelectorDialog() { - return new LightSelectorDialog<>(getChangeConsumer().getCurrentModel(), type, this::addElement); - } - - @Override - @FxThread - protected void reload() { - - var light = getPropertyValue(); - var elementLabel = getElementLabel(); - - String name = light == null ? null : light.getName(); - name = name == null && light != null ? light.getClass().getSimpleName() : name; - - elementLabel.setText(StringUtils.ifEmpty(name, NO_ELEMENT)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java deleted file mode 100644 index ba1332a9..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.MaterialKey; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.StringUtils; -import javafx.event.ActionEvent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The implementation of the {@link MaterialPropertyControl} to edit the {@link MaterialKey}. - * - * @param the type parameter - * @author JavaSaBr - */ -public class MaterialKeyPropertyControl extends MaterialPropertyControl { - - public MaterialKeyPropertyControl( - @Nullable MaterialKey element, - @NotNull String paramName, - @NotNull C changeConsumer - ) { - super(element, paramName, changeConsumer); - } - - @Override - @FxThread - protected void change(@Nullable ActionEvent event) { - UiUtils.openFileAssetDialog(this::addMaterial, MATERIAL_EXTENSIONS, DEFAULT_ACTION_TESTER); - } - - @Override - @FxThread - protected void addMaterial(@NotNull Path file) { - - var assetFile = notNull(getAssetFile(file)); - var materialKey = new MaterialKey(toAssetPath(assetFile)); - - changed(materialKey, getPropertyValue()); - setIgnoreListener(true); - try { - reload(); - } finally { - setIgnoreListener(false); - } - } - - @Override - @FxThread - protected void openToEdit(@Nullable ActionEvent event) { - EditorUtil.openInEditor(getPropertyValue()); - } - - @Override - @FxThread - protected void reload() { - var element = getPropertyValue(); - getMaterialLabel().setText(element == null || StringUtils.isEmpty(element.getName()) ? - NO_MATERIAL : element.getName()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/MaterialPropertyControl.java deleted file mode 100644 index 28bb3fa3..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialPropertyControl.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.material.Material; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.fx.util.FxUtils; -import javafx.event.ActionEvent; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.input.DragEvent; -import javafx.scene.input.TransferMode; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -/** - * The implementation of the {@link PropertyControl} to edit the {@link Material}. - * - * @param the type of a {@link Spatial} - * @param the type of material property - * @author JavaSaBr - */ -public class MaterialPropertyControl extends PropertyControl { - - /** - * The constant NO_MATERIAL. - */ - @NotNull - protected static final String NO_MATERIAL = Messages.MATERIAL_MODEL_PROPERTY_CONTROL_NO_MATERIAL; - - /** - * The constant MATERIAL_EXTENSIONS. - */ - @NotNull - protected static final Array MATERIAL_EXTENSIONS = ArrayFactory.asArray(FileExtensions.JME_MATERIAL); - - /** - * The material name label. - */ - @Nullable - private Label materialLabel; - - public MaterialPropertyControl( - @Nullable V element, - @NotNull String paramName, - @NotNull C changeConsumer - ) { - super(element, paramName, changeConsumer); - setOnDragOver(this::handleDragOverEvent); - setOnDragDropped(this::handleDragDroppedEvent); - setOnDragExited(this::handleDragExitedEvent); - } - - /** - * Handle drag exited events. - * - * @param dragEvent the drag exited event. - */ - @FxThread - private void handleDragExitedEvent(@NotNull DragEvent dragEvent) { - - } - - /** - * Handle dropped events. - * - * @param dragEvent the dropped event. - */ - @FxThread - private void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { - - var files = EditorUtil.getFiles(dragEvent.getDragboard()); - if (files.size() != 1) { - return; - } - - var file = files.get(0); - - if (!file.getName().endsWith(FileExtensions.JME_MATERIAL)) { - return; - } - - addMaterial(file.toPath()); - } - - /** - * Handle drag over events. - * - * @param dragEvent the drag over event. - */ - @FxThread - private void handleDragOverEvent(@NotNull DragEvent dragEvent) { - - var dragboard = dragEvent.getDragboard(); - var files = EditorUtil.getFiles(dragboard); - if (files.size() != 1) { - return; - } - - var file = files.get(0); - - if (!file.getName().endsWith(FileExtensions.JME_MATERIAL)) { - return; - } - - var transferModes = dragboard.getTransferModes(); - var isCopy = transferModes.contains(TransferMode.COPY); - - dragEvent.acceptTransferModes(isCopy ? TransferMode.COPY : TransferMode.MOVE); - dragEvent.consume(); - } - - /** - * Add the mew material. - * - * @param file the file - */ - @FxThread - protected void addMaterial(@NotNull Path file) { - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - materialLabel = new Label(NO_MATERIAL); - - var changeButton = new Button(); - changeButton.setGraphic(new ImageView(Icons.ADD_16)); - changeButton.setOnAction(this::change); - - var editButton = new Button(); - editButton.setGraphic(new ImageView(Icons.EDIT_16)); - editButton.disableProperty().bind(materialLabel.textProperty().isEqualTo(NO_MATERIAL)); - editButton.setOnAction(this::openToEdit); - - materialLabel.prefWidthProperty().bind(widthProperty() - .subtract(changeButton.widthProperty()) - .subtract(editButton.widthProperty())); - - FxUtils.addClass(container, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) - .addClass(materialLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) - .addClass(changeButton, editButton, - CssClasses.FLAT_BUTTON, - CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); - - FxUtils.addChild(container, - materialLabel, changeButton, editButton); - - DynamicIconSupport.addSupport(changeButton, editButton); - } - - /** - * Show dialog to choose another material. - * - * @param event the action event. - */ - @FxThread - protected void change(@Nullable ActionEvent event) { - } - - /** - * Open this material in the material editor. - * - * @param event the action event. - */ - @FxThread - protected void openToEdit(@Nullable ActionEvent event) { - } - - /** - * Get the material name label. - * - * @return the material name label. - */ - @FxThread - protected @NotNull Label getMaterialLabel() { - return notNull(materialLabel); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java deleted file mode 100644 index 188d1c77..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.geom.util.AngleUtils.degreeToRadians; -import static com.ss.rlib.common.geom.util.AngleUtils.radiansToDegree; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Quaternion; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import com.ss.rlib.fx.util.ObservableUtils; -import javafx.scene.control.Label; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit {@link Quaternion} values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class QuaternionPropertyControl extends PropertyControl { - - /** - * The field Y. - */ - @Nullable - private FloatTextField xField; - - /** - * The field X. - */ - @Nullable - private FloatTextField yField; - - /** - * The field Z. - */ - @Nullable - private FloatTextField zField; - - public QuaternionPropertyControl( - @Nullable Quaternion propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - var xLabel = new Label("x:"); - - xField = new FloatTextField(); - xField.setOnKeyReleased(this::keyReleased); - xField.prefWidthProperty() - .bind(widthProperty().divide(3)); - - var yLabel = new Label("y:"); - - yField = new FloatTextField(); - yField.setOnKeyReleased(this::keyReleased); - yField.prefWidthProperty() - .bind(widthProperty().divide(3)); - - var zLabel = new Label("z:"); - - zField = new FloatTextField(); - zField.setOnKeyReleased(this::keyReleased); - zField.prefWidthProperty() - .bind(widthProperty().divide(3)); - - FxControlUtils.onValueChange(xField, this::changeValue); - FxControlUtils.onValueChange(yField, this::changeValue); - FxControlUtils.onValueChange(zField, this::changeValue); - - FxUtils.addClass(xLabel, yLabel, zLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_NUMBER_LABEL) - .addClass(container, - CssClasses.DEF_HBOX, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) - .addClass(xField, yField, zField, - CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD, - CssClasses.TRANSPARENT_TEXT_FIELD); - - FxUtils.addChild(container, - xLabel, xField, - yLabel, yField, - zLabel, zField); - - ObservableUtils.onChange(UiUtils.addFocusBinding(container, xField, yField, zField), - this::applyOnLostFocus); - } - - @Override - @FxThread - protected void setPropertyValue(@Nullable Quaternion quaternion) { - super.setPropertyValue(quaternion == null ? null : quaternion.clone()); - } - - /** - * Get the field X. - * - * @return the field X. - */ - @FxThread - private @NotNull FloatTextField getXField() { - return notNull(xField); - } - - /** - * Get the field Y. - * - * @return the field Y. - */ - @FxThread - private @NotNull FloatTextField getYFiled() { - return notNull(yField); - } - - /** - * Get the field Z. - * - * @return the field Z. - */ - @FxThread - private @NotNull FloatTextField getZField() { - return notNull(zField); - } - - @Override - @FxThread - protected void reload() { - - var angles = new float[3]; - var value = getPropertyValue(); - - if(value != null) { - value.toAngles(angles); - } - - var xField = getXField(); - xField.setValue(radiansToDegree(angles[0])); - xField.positionCaret(xField.getText().length()); - - var yFiled = getYFiled(); - yFiled.setValue(radiansToDegree(angles[1])); - yFiled.positionCaret(yFiled.getText().length()); - - var zField = getZField(); - zField.setValue(radiansToDegree(angles[2])); - zField.positionCaret(zField.getText().length()); - } - - @Override - public boolean isDirty() { - - var angles = new float[3]; - var value = getPropertyValue(); - - if(value != null) { - value.toAngles(angles); - } - - float xValue = getXField().getValue(); - float yValue = getYFiled().getValue(); - float zValue = getZField().getValue(); - - return angles[0] != xValue || angles[1] != yValue || angles[2] != zValue; - } - - /** - * Handle of input the enter key. - */ - @FxThread - private void keyReleased(@NotNull KeyEvent event) { - if (event.getCode() == KeyCode.ENTER) { - changeValue(); - } - } - - /** - * Change value of rotation. - */ - @FxThread - private void changeValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - - var oldValue = getPropertyValue(); - if (oldValue != null) { - oldValue = oldValue.clone(); - } - - var x = degreeToRadians(getXField().getValue()); - var y = degreeToRadians(getYFiled().getValue()); - var z = degreeToRadians(getZField().getValue()); - - var newValue = new Quaternion() - .fromAngles(ArrayFactory.toFloatArray(x, y, z)); - - changed(newValue, oldValue); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/SpatialElementModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/SpatialElementModelPropertyControl.java deleted file mode 100644 index a6ab371f..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/SpatialElementModelPropertyControl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.dialog.node.selector.NodeSelectorDialog; -import com.ss.editor.ui.dialog.node.selector.SpatialSelectorDialog; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link ElementModelPropertyControl} to edit a spatial from a scene. - * - * @param the type of an editing object. - * @param the type of an editing property. - * @author JavaSaBr - */ -public class SpatialElementModelPropertyControl extends ElementModelPropertyControl { - - public SpatialElementModelPropertyControl( - @NotNull Class type, - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull ModelChangeConsumer changeConsumer - ) { - super(type, propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected @NotNull NodeSelectorDialog createNodeSelectorDialog() { - return new SpatialSelectorDialog<>(getChangeConsumer().getCurrentModel(), type, this::addElement); - } - - @Override - @FxThread - protected void reload() { - - var spatial = getPropertyValue(); - - String name = spatial == null ? null : spatial.getName(); - name = name == null && spatial != null ? spatial.getClass().getSimpleName() : name; - - getElementLabel().setText(name == null ? NO_ELEMENT : name); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/StringBasedArrayPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/StringBasedArrayPropertyControl.java deleted file mode 100644 index bb8e8512..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/StringBasedArrayPropertyControl.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.TextField; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit array values. - * - * @param the change consumer's type. - * @param the type of an editing object. - * @param the type of an editing property. - * @author JavaSaBr - */ -public class StringBasedArrayPropertyControl extends PropertyControl { - - /** - * The filed with current value. - */ - @Nullable - private TextField valueField; - - public StringBasedArrayPropertyControl( - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public StringBasedArrayPropertyControl( - @Nullable T propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getValueField(), - widthProperty().multiply(controlWidthPercent)); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - valueField = new TextField(); - valueField.setOnKeyReleased(this::updateValue); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxUtils.addClass(valueField, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, valueField); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the filed with current value. - * - * @return the filed with current value. - */ - @FxThread - protected @NotNull TextField getValueField() { - return notNull(valueField); - } - - /** - * Update the value. - */ - @FxThread - protected void updateValue(@Nullable KeyEvent event) { - if (!isIgnoreListener() && (event == null || event.getCode() == KeyCode.ENTER)) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - changed(getCurrentValue(), getPropertyValue()); - } - - @FxThread - protected @Nullable T getCurrentValue() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java deleted file mode 100644 index b39c20f6..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.StringUtils.emptyIfNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.control.TextField; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit string values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class StringPropertyControl extends PropertyControl { - - /** - * The filed with current value. - */ - @Nullable - private TextField valueField; - - public StringPropertyControl( - @Nullable String propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - valueField = new TextField(); - valueField.setOnKeyReleased(this::updateValue); - valueField.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - FxControlUtils.onFocusChange(valueField, this::applyOnLostFocus); - FxUtils.addClass(valueField, - CssClasses.PROPERTY_CONTROL_COMBO_BOX); - - FxUtils.addChild(container, valueField); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Get the filed with current value. - * - * @return the filed with current value. - */ - @FxThread - private @NotNull TextField getValueField() { - return notNull(valueField); - } - - @Override - @FxThread - protected void reload() { - var valueField = getValueField(); - var caretPosition = valueField.getCaretPosition(); - valueField.setText(emptyIfNull(getPropertyValue())); - valueField.positionCaret(caretPosition); - } - - /** - * Update the value. - */ - @FxThread - private void updateValue(@NotNull KeyEvent event) { - if (!isIgnoreListener() && event.getCode() == KeyCode.ENTER) { - apply(); - } - } - - @FxThread - @Override - public boolean isDirty() { - return !StringUtils.equals(getPropertyValue(), getValueField().getText()); - } - - @Override - @FxThread - protected void apply() { - super.apply(); - changed(getValueField().getText(), getPropertyValue()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Texture2dPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Texture2dPropertyControl.java deleted file mode 100644 index e4f38a6c..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Texture2dPropertyControl.java +++ /dev/null @@ -1,407 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.FileExtensions.TEXTURE_EXTENSIONS; -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_FLIPPED_TEXTURES; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_FLIPPED_TEXTURES; -import static com.ss.editor.extension.property.EditablePropertyType.BOOLEAN; -import static com.ss.editor.extension.property.EditablePropertyType.ENUM; -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.TextureKey; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.tooltip.ImageChannelPreview; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.fx.util.FxUtils; -import javafx.beans.binding.BooleanBinding; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.Tooltip; -import javafx.scene.image.ImageView; -import javafx.scene.input.DragEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The implementation of the {@link PropertyControl} to edit {@link com.jme3.texture.Texture2D} values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class Texture2dPropertyControl extends PropertyControl { - - /** - * The constant NO_TEXTURE. - */ - @NotNull - protected static final String NO_TEXTURE = Messages.MATERIAL_MODEL_PROPERTY_CONTROL_NO_TEXTURE; - - @NotNull - protected static final Point DIALOG_SIZE = new Point(600, -1); - - @NotNull - protected static final String PROP_FLIP = "flip"; - - @NotNull - protected static final String PROP_WRAP_MODE_S = "wrapModeS"; - - @NotNull - protected static final String PROP_WRAP_MODE_T = "wrapModeT"; - - @NotNull - protected static final String PROP_MAG_FILTER = "magFilter"; - - @NotNull - protected static final String PROP_MIN_FILTER = "minFilter"; - - /** - * The image channels preview. - */ - @Nullable - private ImageChannelPreview textureTooltip; - - /** - * The image preview. - */ - @Nullable - private ImageView texturePreview; - - /** - * The label for of path to a texture. - */ - @Nullable - private Label textureLabel; - - /** - * The field container. - */ - @Nullable - private HBox fieldContainer; - - public Texture2dPropertyControl( - @Nullable Texture2D propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - setOnDragOver(this::handleDragOverEvent); - setOnDragDropped(this::handleDragDroppedEvent); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - } - - /** - * Handle drag dropped events. - * - * @param dragEvent the drag dropped event. - */ - @FxThread - protected void handleDragDroppedEvent(@NotNull DragEvent dragEvent) { - UiUtils.handleDroppedFile(dragEvent, TEXTURE_EXTENSIONS, this, Texture2dPropertyControl::changeTexture); - } - - /** - * Handle drag over events. - * - * @param dragEvent the drag over event. - */ - @FxThread - protected void handleDragOverEvent(@NotNull DragEvent dragEvent) { - UiUtils.acceptIfHasFile(dragEvent, TEXTURE_EXTENSIONS); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - fieldContainer = new HBox(); - - if (!isSingleRow()) { - fieldContainer.prefWidthProperty() - .bind(container.widthProperty()); - } - - textureTooltip = new ImageChannelPreview(); - - var previewContainer = new VBox(); - - texturePreview = new ImageView(); - texturePreview.fitHeightProperty() - .bind(previewContainer.heightProperty()); - texturePreview.fitWidthProperty() - .bind(previewContainer.widthProperty()); - - Tooltip.install(texturePreview, textureTooltip); - - var settingsButton = new Button(); - settingsButton.setGraphic(new ImageView(Icons.SETTINGS_16)); - settingsButton.setOnAction(event -> openSettings()); - settingsButton.disableProperty().bind(buildDisableRemoveCondition()); - - var addButton = new Button(); - addButton.setGraphic(new ImageView(Icons.ADD_12)); - addButton.setOnAction(event -> addNewTexture()); - - var removeButton = new Button(); - removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); - removeButton.setOnAction(event -> removeTexture()); - removeButton.disableProperty().bind(buildDisableRemoveCondition()); - - if (!isSingleRow()) { - - textureLabel = new Label(NO_TEXTURE); - textureLabel.prefWidthProperty() - .bind(widthProperty() - .subtract(removeButton.widthProperty()) - .subtract(previewContainer.widthProperty()) - .subtract(settingsButton.widthProperty()) - .subtract(addButton.widthProperty())); - - FxUtils.addClass(textureLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_ELEMENT_LABEL) - .addClass(fieldContainer, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER); - - FxUtils.addChild(fieldContainer, textureLabel); - - } else { - FxUtils.addClass(fieldContainer, - CssClasses.TEXT_INPUT_CONTAINER_WITHOUT_PADDING); - } - - FxUtils.addClass(previewContainer, - CssClasses.ABSTRACT_PARAM_CONTROL_PREVIEW_CONTAINER) - .addClass(settingsButton, addButton, removeButton, - CssClasses.FLAT_BUTTON, - CssClasses.INPUT_CONTROL_TOOLBAR_BUTTON); - - FxUtils.addChild(fieldContainer, previewContainer, addButton, settingsButton, removeButton) - .addChild(container, fieldContainer) - .addChild(previewContainer, texturePreview); - } - - /** - * Get the disable|remove condition. - * - * @return the disable|remove condition. - */ - @FxThread - protected @NotNull BooleanBinding buildDisableRemoveCondition() { - return getTexturePreview().imageProperty().isNull(); - } - - /** - * Get the texture label. - * - * @return the texture label. - */ - @FxThread - private @NotNull Label getTextureLabel() { - return notNull(textureLabel); - } - - /** - * Get the field container. - * - * @return the field container. - */ - @FxThread - protected @NotNull HBox getFieldContainer() { - return notNull(fieldContainer); - } - - /** - * Get the texture preview. - * - * @return the texture preview. - */ - @FxThread - private @NotNull ImageView getTexturePreview() { - return notNull(texturePreview); - } - - /** - * Get the image channels preview. - * - * @return the image channels preview. - */ - @FxThread - private @NotNull ImageChannelPreview getTextureTooltip() { - return notNull(textureTooltip); - } - - /** - * Remove the current texture. - */ - @FxThread - protected void removeTexture() { - changeTexture(null); - } - - /** - * Open the dialog to choose a new texture. - */ - @FxThread - protected void addNewTexture() { - UiUtils.openFileAssetDialog(this::changeTexture, TEXTURE_EXTENSIONS, DEFAULT_ACTION_TESTER); - } - - /** - * Open a dialog with texture's settings. - */ - @FxThread - protected void openSettings() { - - var texture = notNull(getPropertyValue()); - var key = (TextureKey) texture.getKey(); - var flipY = key.isFlipY(); - var wrapS = texture.getWrap(Texture.WrapAxis.S); - var wrapT = texture.getWrap(Texture.WrapAxis.T); - var magFilter = texture.getMagFilter(); - var minFilter = texture.getMinFilter(); - - var properties = ArrayFactory.newArray(PropertyDefinition.class); - properties.add(new PropertyDefinition(BOOLEAN, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_FLIP_Y, PROP_FLIP, flipY)); - properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_WRAP_MODE_S, PROP_WRAP_MODE_S, wrapS)); - properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_WRAP_MODE_T, PROP_WRAP_MODE_T, wrapT)); - properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_MAG_FILTER, PROP_MAG_FILTER, magFilter)); - properties.add(new PropertyDefinition(ENUM, Messages.MATERIAL_MODEL_PROPERTY_CONTROL_MIN_FILTER, PROP_MIN_FILTER, minFilter)); - - var dialog = new GenericFactoryDialog(properties, this::applyChanges); - dialog.setTitle(Messages.MATERIAL_MODEL_PROPERTY_CONTROL_TEXTURE_SETTINGS); - dialog.setButtonOkText(Messages.SIMPLE_DIALOG_BUTTON_APPLY); - dialog.setButtonCloseText(Messages.SIMPLE_DIALOG_BUTTON_CANCEL); - dialog.configureSize(DIALOG_SIZE); - dialog.show(); - } - - /** - * Apply new changes if need. - * - * @param vars the vars table. - */ - @FxThread - private void applyChanges(@NotNull VarTable vars) { - - var texture = notNull(getPropertyValue()); - var key = (TextureKey) texture.getKey(); - var flipY = key.isFlipY(); - var wrapS = texture.getWrap(Texture.WrapAxis.S); - var wrapT = texture.getWrap(Texture.WrapAxis.T); - var magFilter = texture.getMagFilter(); - var minFilter = texture.getMinFilter(); - - var needFlipY = vars.getBoolean(PROP_FLIP); - var needWrapS = vars.getEnum(PROP_WRAP_MODE_S, Texture.WrapMode.class); - var needWrapT = vars.getEnum(PROP_WRAP_MODE_T, Texture.WrapMode.class); - var needMagFilter = vars.getEnum(PROP_MAG_FILTER, Texture.MagFilter.class); - var needMinFilter = vars.getEnum(PROP_MIN_FILTER, Texture.MinFilter.class); - - if (flipY == needFlipY && - wrapS == needWrapS && - wrapT == needWrapT && - magFilter == needMagFilter && - minFilter == needMinFilter) { - return; - } - - var newKey = new TextureKey(key.getName()); - newKey.setFlipY(needFlipY); - - var assetManager = EditorUtil.getAssetManager(); - assetManager.deleteFromCache(key); - - var loadedTexture = (Texture2D) assetManager.loadTexture(newKey); - loadedTexture.setWrap(Texture.WrapAxis.S, needWrapS); - loadedTexture.setWrap(Texture.WrapAxis.T, needWrapT); - loadedTexture.setMagFilter(needMagFilter); - loadedTexture.setMinFilter(needMinFilter); - - changed(loadedTexture, texture); - } - - /** - * Change a texture to the file. - * - * @param file the file of a new texture. - */ - @FxThread - protected void changeTexture(@Nullable Path file) { - - if (file == null) { - changed(null, getPropertyValue()); - } else { - - var config = EditorConfig.getInstance(); - var assetFile = notNull(getAssetFile(file)); - var textureKey = new TextureKey(toAssetPath(assetFile)); - textureKey.setFlipY(config.getBoolean(PREF_FLIPPED_TEXTURES, PREF_DEFAULT_FLIPPED_TEXTURES)); - - var texture = (Texture2D) EditorUtil.getAssetManager() - .loadTexture(textureKey); - texture.setWrap(Texture.WrapMode.Repeat); - - changed(texture, getPropertyValue()); - } - } - - @Override - @FxThread - protected void reload() { - - var texture2D = getPropertyValue(); - var key = texture2D == null ? null : texture2D.getKey(); - - if (!isSingleRow()) { - getTextureLabel().setText(key == null ? NO_TEXTURE : key.getName()); - } - - var textureTooltip = getTextureTooltip(); - var preview = getTexturePreview(); - - if (key == null) { - preview.setImage(null); - textureTooltip.clean(); - preview.setDisable(true); - preview.setMouseTransparent(true); - } else { - - preview.setDisable(false); - preview.setMouseTransparent(false); - - var realFile = notNull(getRealFile(key.getName())); - - if (Files.exists(realFile)) { - preview.setImage(IMAGE_MANAGER.getImagePreview(realFile, 24, 24)); - textureTooltip.showImage(realFile); - } else { - preview.setImage(IMAGE_MANAGER.getImagePreview(key.getName(), 24, 24)); - textureTooltip.showImage(key.getName()); - } - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector2fPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector2fPropertyControl.java deleted file mode 100644 index a973eb09..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector2fPropertyControl.java +++ /dev/null @@ -1,249 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.util.GeomUtils.zeroIfNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Vector2f; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.GeomUtils; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit {@link Vector2f} values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class Vector2fPropertyControl extends PropertyControl { - - /** - * The field X. - */ - @Nullable - private FloatTextField xField; - - /** - * The field Y. - */ - @Nullable - private FloatTextField yField; - - /** - * The field container. - */ - @Nullable - private HBox fieldContainer; - - public Vector2fPropertyControl( - @Nullable Vector2f propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getFieldContainer(), - widthProperty().multiply(controlWidthPercent)); - } - - /** - * Set value limits for this field. - * - * @param min the min value. - * @param max the max value. - */ - @FxThread - public void setMinMax(float min, float max) { - getXField().setMinMax(min, max); - getYField().setMinMax(min, max); - } - - /** - * Sets the scroll power. - * - * @param scrollPower the scroll power. - */ - @FxThread - public void setScrollPower(float scrollPower) { - getXField().setScrollPower(scrollPower); - getYField().setScrollPower(scrollPower); - } - - /** - * Get the scroll power. - * - * @return the scroll power. - */ - @FxThread - public float getScrollPower() { - return getXField().getScrollPower(); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - fieldContainer = new HBox(); - fieldContainer.prefWidthProperty() - .bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - xField = new FloatTextField(); - xField.setOnKeyReleased(this::updateVector); - xField.addChangeListener((observable, oldValue, newValue) -> updateVector(null)); - xField.prefWidthProperty().bind(fieldContainer.widthProperty().multiply(0.5)); - xField.setScrollPower(10F); - - yField = new FloatTextField(); - yField.setOnKeyReleased(this::updateVector); - yField.addChangeListener((observable, oldValue, newValue) -> updateVector(null)); - yField.prefWidthProperty().bind(fieldContainer.widthProperty().multiply(0.5)); - yField.setScrollPower(10F); - - FxUtils.addClass(fieldContainer, - CssClasses.DEF_HBOX, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_SHORT_INPUT_CONTAINER) - .addClass(xField, yField, - CssClasses.TRANSPARENT_TEXT_FIELD); - - FxUtils.addChild(fieldContainer, xField, yField) - .addChild(container, fieldContainer); - - UiUtils.addFocusBinding(fieldContainer, xField, yField) - .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); - } - - /** - * Get the field container. - * - * @return the field container. - */ - @FxThread - private @NotNull HBox getFieldContainer() { - return notNull(fieldContainer); - } - - @Override - @FxThread - protected void setPropertyValue(@Nullable Vector2f vector) { - super.setPropertyValue(zeroIfNull(vector).clone()); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Check the result x value. - * - * @param x the x. - * @param y the y. - * @return the result x value. - */ - @FxThread - protected float checkResultXValue(float x, float y) { - return x; - } - - /** - * Check result y value. - * - * @param x the x. - * @param y the y. - * @return the result y value. - */ - @FxThread - protected float checkResultYValue(float x, float y) { - return y; - } - - /** - * Get the X field. - * - * @return the X field. - */ - @FxThread - protected @NotNull FloatTextField getXField() { - return notNull(xField); - } - - /** - * Get the Y field. - * - * @return the Y field. - */ - @FxThread - protected @NotNull FloatTextField getYField() { - return notNull(yField); - } - - @Override - @FxThread - protected void reload() { - - var vector = zeroIfNull(getPropertyValue()); - - var xField = getXField(); - xField.setValue(vector.getX()); - xField.positionCaret(xField.getText().length()); - - var yField = getYField(); - yField.setValue(vector.getY()); - yField.positionCaret(yField.getText().length()); - } - - @Override - @FxThread - public boolean isDirty() { - - var x = getXField().getValue(); - var y = getYField().getValue(); - - return !GeomUtils.equals(getPropertyValue(), x, y); - } - - /** - * Update the vector. - * - * @param event the event - */ - @FxThread - private void updateVector(@Nullable KeyEvent event) { - if (!isIgnoreListener() && (event == null || event.getCode() == KeyCode.ENTER)) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - - var x = getXField().getValue(); - var y = getYField().getValue(); - - var oldValue = zeroIfNull(getPropertyValue()); - var newValue = new Vector2f(checkResultXValue(x, y), checkResultYValue(x, y)); - - changed(newValue, oldValue.clone()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fPropertyControl.java deleted file mode 100644 index 8f3a7544..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fPropertyControl.java +++ /dev/null @@ -1,227 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.util.GeomUtils.zeroIfNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.GeomUtils; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.control.Label; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit {@link Vector3f} values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr - */ -public class Vector3fPropertyControl extends PropertyControl { - - /** - * The field X. - */ - @Nullable - private FloatTextField xField; - - /** - * The field Y. - */ - @Nullable - private FloatTextField yField; - - /** - * The field Z. - */ - @Nullable - private FloatTextField zField; - - public Vector3fPropertyControl( - @Nullable Vector3f propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - super(propertyValue, propertyName, changeConsumer); - } - - public Vector3fPropertyControl( - @Nullable Vector3f propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer, - @Nullable ChangeHandler changeHandler - ) { - super(propertyValue, propertyName, changeConsumer, changeHandler); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - var xLabel = new Label("x:"); - - xField = new FloatTextField(); - xField.setOnKeyReleased(this::keyReleased); - xField.setScrollPower(getScrollPower()); - xField.prefWidthProperty(). - bind(widthProperty().divide(3)); - - var yLabel = new Label("y:"); - - yField = new FloatTextField(); - yField.setOnKeyReleased(this::keyReleased); - yField.setScrollPower(getScrollPower()); - yField.prefWidthProperty() - .bind(widthProperty().divide(3)); - - var zLabel = new Label("z:"); - - zField = new FloatTextField(); - zField.setOnKeyReleased(this::keyReleased); - zField.setScrollPower(getScrollPower()); - zField.prefWidthProperty() - .bind(widthProperty().divide(3)); - - FxControlUtils.onValueChange(xField, this::changeValue); - FxControlUtils.onValueChange(yField, this::changeValue); - FxControlUtils.onValueChange(zField, this::changeValue); - - FxUtils.addClass(xLabel, yLabel, zLabel, - CssClasses.ABSTRACT_PARAM_CONTROL_NUMBER_LABEL) - .addClass(container, - CssClasses.DEF_HBOX, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_INPUT_CONTAINER) - .addClass(xField, yField, zField, - CssClasses.PROPERTY_CONTROL_VECTOR_3F_FIELD, - CssClasses.TRANSPARENT_TEXT_FIELD); - - FxUtils.addChild(container, - xLabel, xField, - yLabel, yField, - zLabel, zField); - - UiUtils.addFocusBinding(container, xField, yField, zField) - .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); - } - - @Override - @FxThread - protected void setPropertyValue(@Nullable Vector3f vector) { - super.setPropertyValue(zeroIfNull(vector).clone()); - } - - /** - * Get the scroll power. - * - * @return the scroll power. - */ - @FxThread - protected float getScrollPower() { - return 10F; - } - - /** - * Get the field X. - * - * @return the field X. - */ - @FxThread - protected @NotNull FloatTextField getXField() { - return notNull(xField); - } - - /** - * Get the filed Y. - * - * @return the field Y. - */ - @FxThread - protected @NotNull FloatTextField getYField() { - return notNull(yField); - } - - /** - * Get the field Z. - * - * @return the field Z. - */ - @FxThread - protected @NotNull FloatTextField getZField() { - return notNull(zField); - } - - @Override - @FxThread - protected void reload() { - - var vector = zeroIfNull(getPropertyValue()); - - var xField = getXField(); - xField.setValue(vector.getX()); - xField.positionCaret(xField.getText().length()); - - var yFiled = getYField(); - yFiled.setValue(vector.getY()); - yFiled.positionCaret(xField.getText().length()); - - var zField = getZField(); - zField.setValue(vector.getZ()); - zField.positionCaret(xField.getText().length()); - } - - @Override - @FxThread - public boolean isDirty() { - - var x = getXField().getValue(); - var y = getYField().getValue(); - var z = getZField().getValue(); - - return !GeomUtils.equals(getPropertyValue(), x, y, z); - } - - /** - * Handle of input the enter key. - */ - @FxThread - private void keyReleased(@NotNull KeyEvent event) { - if (event.getCode() == KeyCode.ENTER) { - changeValue(); - } - } - - /** - * Change value of vector. - */ - @FxThread - private void changeValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - - var x = getXField().getValue(); - var y = getYField().getValue(); - var z = getZField().getValue(); - - var storedValue = zeroIfNull(getPropertyValue()); - - changed(new Vector3f(x, y, z), storedValue.clone()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fSingleRowPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fSingleRowPropertyControl.java deleted file mode 100644 index 786d6704..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3fSingleRowPropertyControl.java +++ /dev/null @@ -1,273 +0,0 @@ -package com.ss.editor.ui.control.property.impl; - -import static com.ss.editor.util.GeomUtils.zeroIfNull; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.property.PropertyControl; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.GeomUtils; -import com.ss.rlib.fx.control.input.FloatTextField; -import com.ss.rlib.fx.util.FxControlUtils; -import com.ss.rlib.fx.util.FxUtils; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyControl} to edit {@link com.jme3.math.Vector3f} values. - * - * @param the type of a change consumer. - * @param the type of an editing object. - * @author JavaSaBr. - */ -public class Vector3fSingleRowPropertyControl extends PropertyControl { - - /** - * The field X. - */ - @Nullable - private FloatTextField xField; - - /** - * The field Y. - */ - @Nullable - private FloatTextField yField; - - /** - * The field Z. - */ - @Nullable - private FloatTextField zField; - - /** - * The field container. - */ - @Nullable - private HBox fieldContainer; - - public Vector3fSingleRowPropertyControl( - @Nullable Vector3f propertyValue, - @NotNull String propertyName, - @NotNull C changeConsumer - ) { - - super(propertyValue, propertyName, changeConsumer); - } - - @Override - @FxThread - public void changeControlWidthPercent(double controlWidthPercent) { - super.changeControlWidthPercent(controlWidthPercent); - - FxUtils.rebindPrefWidth(getFieldContainer(), - widthProperty().multiply(controlWidthPercent)); - } - - @Override - @FxThread - protected void createComponents(@NotNull HBox container) { - super.createComponents(container); - - fieldContainer = new HBox(); - fieldContainer.prefWidthProperty().bind(widthProperty().multiply(CONTROL_WIDTH_PERCENT)); - - xField = new FloatTextField(); - xField.setOnKeyReleased(this::keyReleased); - xField.setScrollPower(10F); - xField.prefWidthProperty(). - bind(fieldContainer.widthProperty().multiply(0.33)); - - yField = new FloatTextField(); - yField.setOnKeyReleased(this::keyReleased); - yField.setScrollPower(10F); - yField.prefWidthProperty() - .bind(fieldContainer.widthProperty().multiply(0.33)); - - zField = new FloatTextField(); - zField.setOnKeyReleased(this::keyReleased); - zField.setScrollPower(10F); - zField.prefWidthProperty() - .bind(fieldContainer.widthProperty().multiply(0.33)); - - FxControlUtils.onValueChange(xField, this::changeValue); - FxControlUtils.onValueChange(yField, this::changeValue); - FxControlUtils.onValueChange(zField, this::changeValue); - - FxUtils.addClass(fieldContainer, - CssClasses.DEF_HBOX, - CssClasses.TEXT_INPUT_CONTAINER, - CssClasses.ABSTRACT_PARAM_CONTROL_SHORT_INPUT_CONTAINER) - .addClass(xField, yField, zField, - CssClasses.TRANSPARENT_TEXT_FIELD); - - FxUtils.addChild(fieldContainer, xField, yField, zField) - .addChild(container, fieldContainer); - - UiUtils.addFocusBinding(fieldContainer, xField, yField, zField) - .addListener((observable, oldValue, newValue) -> applyOnLostFocus(newValue)); - } - - /** - * Get the field container. - * - * @return the field container. - */ - @FxThread - private @NotNull HBox getFieldContainer() { - return notNull(fieldContainer); - } - - @Override - @FxThread - protected void setPropertyValue(@Nullable Vector3f vector) { - super.setPropertyValue(zeroIfNull(vector).clone()); - } - - @Override - @FromAnyThread - protected boolean isSingleRow() { - return true; - } - - /** - * Check result x value. - * - * @param x the x. - * @param y the y. - * @param z the z. - * @return the result x value. - */ - @FxThread - protected float checkResultXValue(float x, float y, float z) { - return x; - } - - /** - * Check result y value. - * - * @param x the x. - * @param y the y. - * @param z the z. - * @return the result y value. - */ - @FxThread - protected float checkResultYValue(float x, float y, float z) { - return y; - } - - /** - * Check result z value. - * - * @param x the x. - * @param y the y. - * @param z the z. - * @return the result z value. - */ - @FxThread - protected float checkResultZValue(float x, float y, float z) { - return z; - } - - /** - * Get the X field. - * - * @return the X field. - */ - @FxThread - protected @NotNull FloatTextField getXField() { - return notNull(xField); - } - - /** - * Get the Y field. - * - * @return the Y field. - */ - @FxThread - protected @NotNull FloatTextField getYField() { - return notNull(yField); - } - - /** - * Get the Z field. - * - * @return the Z field. - */ - @FxThread - protected @NotNull FloatTextField getZField() { - return notNull(zField); - } - - @Override - @FxThread - protected void reload() { - - var vector = zeroIfNull(getPropertyValue()); - - var xField = getXField(); - xField.setValue(vector.getX()); - xField.positionCaret(xField.getText().length()); - - var yField = getYField(); - yField.setValue(vector.getY()); - yField.positionCaret(yField.getText().length()); - - var zField = getZField(); - zField.setValue(vector.getZ()); - zField.positionCaret(zField.getText().length()); - } - - @Override - @FxThread - public boolean isDirty() { - - var x = getXField().getValue(); - var y = getYField().getValue(); - var z = getZField().getValue(); - - return !GeomUtils.equals(getPropertyValue(), x, y, z); - } - - /** - * Handle of input the enter key. - */ - @FxThread - private void keyReleased(@NotNull KeyEvent event) { - if (event.getCode() == KeyCode.ENTER) { - changeValue(); - } - } - - /** - * Change value of vector. - */ - @FxThread - private void changeValue() { - if (!isIgnoreListener()) { - apply(); - } - } - - @Override - @FxThread - protected void apply() { - super.apply(); - - var x = getXField().getValue(); - var y = getYField().getValue(); - var z = getZField().getValue(); - - var oldValue = zeroIfNull(getPropertyValue()); - var newValue = new Vector3f(); - newValue.set(checkResultXValue(x, y, z), checkResultYValue(x, y, z), checkResultZValue(x, y, z)); - - changed(newValue, oldValue.clone()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java deleted file mode 100644 index 9d9d2a9e..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/impl/particle/ParticleEmitterImagesModelPropertyControl.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ss.editor.ui.control.property.impl.particle; - -import com.jme3.effect.ParticleEmitter; -import com.jme3.math.Vector2f; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.property.impl.Vector2fPropertyControl; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link Vector2fPropertyControl} to edit images count of the {@link - * ParticleEmitter}*. - * - * @author JavaSaBr. - */ -public class ParticleEmitterImagesModelPropertyControl extends Vector2fPropertyControl { - - public ParticleEmitterImagesModelPropertyControl( - @NotNull Vector2f element, - @NotNull String paramName, - @NotNull ModelChangeConsumer changeConsumer - ) { - super(element, paramName, changeConsumer); - getXField().setMinMax(1, Integer.MAX_VALUE); - getYField().setMinMax(1, Integer.MAX_VALUE); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyCountOperation.java b/src/main/java/com/ss/editor/ui/control/property/operation/PropertyCountOperation.java deleted file mode 100644 index 8895c3f7..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyCountOperation.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.ui.control.property.operation; - -import com.ss.editor.model.undo.editor.ChangeConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link PropertyOperation} to edit property count of objects. - * - * @param the type of changed consumer - * @param the type of edited object - * @param the type of edited property - * @author JavaSaBr - */ -public class PropertyCountOperation extends PropertyOperation { - - public PropertyCountOperation(@NotNull final D target, @NotNull final String propertyName, - @Nullable final T newValue, @Nullable final T oldValue) { - super(target, propertyName, newValue, oldValue); - } - - @Override - protected void redoImpl(@NotNull final C editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - apply(target, newValue); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangePropertyCount(target)); - }); - } - - @Override - protected void undoImpl(@NotNull final C editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - apply(target, oldValue); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangePropertyCount(target)); - }); - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java b/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java deleted file mode 100644 index 98c70b8b..00000000 --- a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ss.editor.ui.control.property.operation; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.impl.AbstractEditorOperation; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiConsumer; - -/** - * The implementation of the {@link AbstractEditorOperation} to edit properties of objects. - * - * @param the type of changed consumer - * @param the type of edited object - * @param the type of edited property - * @author JavaSaBr - */ -public class PropertyOperation extends AbstractEditorOperation { - - /** - * The property name. - */ - @NotNull - protected final String propertyName; - - /** - * The new value of the property. - */ - @Nullable - protected final T newValue; - - /** - * The old value of the property. - */ - @Nullable - protected final T oldValue; - - /** - * The target object. - */ - protected final D target; - - /** - * The handler for applying new value. - */ - private BiConsumer applyHandler; - - public PropertyOperation(@NotNull final D target, @NotNull final String propertyName, @Nullable final T newValue, - @Nullable final T oldValue) { - this.newValue = newValue; - this.oldValue = oldValue; - this.target = target; - this.propertyName = propertyName; - } - - @Override - @FxThread - protected void redoImpl(@NotNull final C editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - editor.notifyJmePreChangeProperty(target, propertyName); - apply(target, newValue); - editor.notifyJmeChangedProperty(target, propertyName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(target, propertyName)); - }); - } - - @Override - @FxThread - protected void undoImpl(@NotNull final C editor) { - EXECUTOR_MANAGER.addJmeTask(() -> { - editor.notifyJmePreChangeProperty(target, propertyName); - apply(target, oldValue); - editor.notifyJmeChangedProperty(target, propertyName); - EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(target, propertyName)); - }); - } - - /** - * Sets apply handler. - * - * @param applyHandler the handler for applying new value. - */ - public void setApplyHandler(@NotNull final BiConsumer applyHandler) { - this.applyHandler = applyHandler; - } - - /** - * Apply new value of the property to the model. - * - * @param spatial the spatial - * @param value the value - */ - protected void apply(@NotNull final D spatial, @Nullable final T value) { - try { - applyHandler.accept(spatial, value); - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java b/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java deleted file mode 100644 index b5f0634b..00000000 --- a/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.ss.editor.ui.control.scene; - -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.control.SelectionMode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; - -/** - * The implementation of {@link NodeTree} to present scene's objects. - * - * @author JavaSaBr - */ -public class SceneNodeTree extends NodeTree { - - public SceneNodeTree(@NotNull final Consumer> selectionHandler, @Nullable final SceneChangeConsumer consumer) { - super(selectionHandler, consumer, SelectionMode.SINGLE); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java deleted file mode 100644 index ce54e05a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.ss.editor.ui.control.tree.action; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of an action for an element in a node tree. - * - * @param the change consumer's type. - * @author JavaSaBr - */ -public abstract class AbstractNodeAction extends MenuItem implements Comparable { - - /** - * The logger. - */ - @NotNull - protected static final Logger LOGGER = LoggerManager.getLogger(AbstractNodeAction.class); - - /** - * The executor manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - @NotNull - private static final Array> EMPTY_NODES = ArrayFactory.newArray(TreeNode.class); - - /** - * The component of the node tree. - */ - @NotNull - private final NodeTree nodeTree; - - /** - * The node. - */ - @NotNull - private final TreeNode node; - - /** - * The nodes. - */ - @NotNull - private final Array> nodes; - - public AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - this(nodeTree, node, EMPTY_NODES); - } - - public AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final Array> nodes) { - this(nodeTree, notNull(nodes.first()), nodes); - } - - AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node, @NotNull final Array> nodes) { - this.nodeTree = unsafeCast(nodeTree); - this.node = node; - this.nodes = nodes; - setOnAction(event -> process()); - setText(getName()); - - final Image icon = getIcon(); - - if (icon != null) { - setGraphic(new ImageView(icon)); - } - } - - /** - * Get the action's name. - * - * @return the action's name. - */ - @FxThread - protected abstract @NotNull String getName(); - - /** - * Execute this action. - */ - @FxThread - protected void process() { - GAnalytics.sendEvent(GAEvent.Category.EDITOR, GAEvent.Action.EXECUTE_NODE_ACTION, getClass().getSimpleName()); - } - - /** - * The icon of this action. - * - * @return the icon or null. - */ - @FxThread - protected @Nullable Image getIcon() { - return null; - } - - /** - * Get the node tree. - * - * @return the component of the model three. - */ - @FxThread - protected @NotNull NodeTree getNodeTree() { - return nodeTree; - } - - /** - * Get the node. - * - * @return the node. - */ - @FxThread - protected @NotNull TreeNode getNode() { - return node; - } - - /** - * Get the nodes. - * - * @return the nodes. - */ - @FxThread - protected @NotNull Array> getNodes() { - return nodes; - } - - /** - * Get the order. - * - * @return the order. - */ - @FxThread - protected int getOrder() { - return 0; - } - - @Override - public int compareTo(@NotNull final MenuItem item) { - if (!(item instanceof AbstractNodeAction)) { - return 0; - } else { - return ((AbstractNodeAction) item).getOrder() - getOrder(); - } - } - - @Override - public String toString() { - return "AbstractNodeAction{name = " + getNode() + "} " + super.toString(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CopyNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CopyNodeAction.java deleted file mode 100644 index d1aea2bc..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CopyNodeAction.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.editor.ui.control.tree.NodeTreeCell.DATA_FORMAT; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to copy a node in model. - * - * @author JavaSaBr - */ -public class CopyNodeAction extends AbstractNodeAction { - - public CopyNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_COPY; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.COPY_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - - final ClipboardContent content = new ClipboardContent(); - content.put(DATA_FORMAT, node.getObjectId()); - - final Clipboard clipboard = Clipboard.getSystemClipboard(); - clipboard.setContent(content); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateEditableSkyAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateEditableSkyAction.java deleted file mode 100644 index 82171341..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateEditableSkyAction.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.dialog.sky.CreateEditableSkyDialog; -import com.ss.editor.ui.dialog.sky.CreateSkyDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create SS sky. - * - * @author JavaSaBr - */ -public class CreateEditableSkyAction extends CreateSkyAction { - - public CreateEditableSkyAction(final @NotNull NodeTree nodeTree, final @NotNull TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_EDITABLE_SKY; - } - - @Override - @FxThread - protected @NotNull CreateSkyDialog createDialog() { - return new CreateEditableSkyDialog(getNode(), getNodeTree()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java deleted file mode 100644 index c6cad750..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.editor.util.EditorUtil.getDefaultLayer; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a node. - * - * @author JavaSaBr - */ -public class CreateNodeAction extends AbstractNodeAction { - - public CreateNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.NODE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_NODE; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final Node node = new Node("New Node"); - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - final SceneLayer defaultLayer = getDefaultLayer(consumer); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, node); - } - - consumer.execute(new AddChildOperation(node, parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateSkyAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateSkyAction.java deleted file mode 100644 index aa2986aa..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateSkyAction.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.dialog.sky.CreateSkyDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create sky. - * - * @author JavaSaBr - */ -public class CreateSkyAction extends AbstractNodeAction { - - public CreateSkyAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.SKY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_SKY; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final CreateSkyDialog dialog = createDialog(); - dialog.show(); - } - - @FxThread - protected @NotNull CreateSkyDialog createDialog() { - return new CreateSkyDialog(getNode(), getNodeTree()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java deleted file mode 100644 index fc09fce6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.DisableControlsOperation; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to disable all controls in a selected node. - * - * @author JavaSaBr - */ -public class DisableAllControlsAction extends AbstractNodeAction { - - public DisableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.STOP_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_DISABLE_ALL_CONTROLS; - } - - @Override - @FxThread - protected void process() { - - final Array controls = NodeUtils.children((Spatial) getNode().getElement()) - .flatMap(ControlUtils::controls) - .filter(ControlUtils::isEnabled) - .collect(toArray(Control.class)); - - final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); - changeConsumer.execute(new DisableControlsOperation(controls)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java deleted file mode 100644 index a24d0936..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static com.ss.rlib.common.util.array.ArrayCollectors.toArray; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.EnableControlsOperation; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to enable all controls in a selected node. - * - * @author JavaSaBr - */ -public class EnableAllControlsAction extends AbstractNodeAction { - - public EnableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PLAY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ENABLE_ALL_CONTROLS; - } - - @Override - @FxThread - protected void process() { - - final Array controls = NodeUtils.children((Spatial) getNode().getElement()) - .flatMap(ControlUtils::controls) - .filter(control -> !ControlUtils.isEnabled(control)) - .collect(toArray(Control.class)); - - final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); - changeConsumer.execute(new EnableControlsOperation(controls)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java deleted file mode 100644 index 065bf0dd..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The implementation of the {@link AbstractNodeAction} for loading the {@link Spatial} to the editor. - * - * @author vp -byte - */ -public class LinkModelAction extends AbstractNodeAction { - - @NotNull - private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || - type == DeleteFileAction.class || - type == RenameFileAction.class; - - @NotNull - private static final Array MODEL_EXTENSIONS = ArrayFactory.newArray(String.class); - - static { - MODEL_EXTENSIONS.add(FileExtensions.JME_OBJECT); - } - - public LinkModelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.LINK_FILE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_LINK_MODEL; - } - - @FxThread - @Override - protected void process() { - super.process(); - UiUtils.openFileAssetDialog(this::processOpen, MODEL_EXTENSIONS, ACTION_TESTER); - } - - /** - * The process of opening file. - * - * @param file the file - */ - @FxThread - protected void processOpen(@NotNull final Path file) { - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - final SceneLayer defaultLayer = EditorUtil.getDefaultLayer(consumer); - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - final ModelKey modelKey = new ModelKey(assetPath); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Spatial loadedModel = assetManager.loadModel(modelKey); - - final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); - assetLinkNode.attachLinkedChild(loadedModel, modelKey); - assetLinkNode.setUserData(KEY_LOADED_MODEL, true); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, assetLinkNode); - } - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - consumer.execute(new AddChildOperation(assetLinkNode, parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java deleted file mode 100644 index 2f27d980..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The implementation of the {@link AbstractNodeAction} for loading the {@link Spatial} to the editor. - * - * @author JavaSaBr - */ -public class LoadModelAction extends AbstractNodeAction { - - @NotNull - private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || - type == DeleteFileAction.class || - type == RenameFileAction.class; - - @NotNull - private static final Array MODEL_EXTENSIONS = ArrayFactory.newArray(String.class); - - static { - MODEL_EXTENSIONS.add(FileExtensions.JME_OBJECT); - } - - public LoadModelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.OPEN_FILE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_LOAD_MODEL; - } - - @Override - @FxThread - protected void process() { - super.process(); - UiUtils.openFileAssetDialog(this::processOpen, MODEL_EXTENSIONS, ACTION_TESTER); - } - - /** - * The process of opening file. - * - * @param file the file - */ - @FxThread - protected void processOpen(@NotNull final Path file) { - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - final SceneLayer defaultLayer = getDefaultLayer(consumer); - - final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); - final String assetPath = toAssetPath(assetFile); - - final ModelKey modelKey = new ModelKey(assetPath); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Spatial loadedModel = assetManager.loadModel(modelKey); - loadedModel.setUserData(KEY_LOADED_MODEL, true); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, loadedModel); - } - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - consumer.execute(new AddChildOperation(loadedModel, parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java deleted file mode 100644 index 839b90f4..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/MakeAsEmbeddedMaterialAction.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetKey; -import com.jme3.material.Material; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link AbstractNodeAction} to make a material as embedded. - * - * @author JavaSaBr - */ -public class MakeAsEmbeddedMaterialAction extends AbstractNodeAction { - - public MakeAsEmbeddedMaterialAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.INFLUENCER_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_MAKE_EMBEDDED; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - final Material material = (Material) node.getElement(); - - final PropertyOperation operation = - new PropertyOperation<>(material, "AssetKey", null, material.getKey()); - operation.setApplyHandler(Material::setKey); - - final ChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); - changeConsumer.execute(operation); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java deleted file mode 100644 index 8fe4747d..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.OptimizeGeometryOperation; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import jme3tools.optimize.GeometryBatchFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to optimize a geometry. - * - * @author JavaSaBr - */ -public class OptimizeGeometryAction extends AbstractNodeAction { - - public OptimizeGeometryAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.INFLUENCER_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_OPTIMIZE_GEOMETRY; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final TreeNode node = getNode(); - final Node oldElement = (Node) node.getElement(); - final Node newElement = (Node) oldElement.clone(); - - GeometryBatchFactory.optimize(newElement); - - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new OptimizeGeometryOperation(newElement, oldElement, oldElement.getParent())); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/PasteNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/PasteNodeAction.java deleted file mode 100644 index b13a4c52..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/PasteNodeAction.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to paste a node in model. - * - * @author JavaSaBr - */ -public class PasteNodeAction extends AbstractNodeAction { - - /** - * The copied node. - */ - @NotNull - private final TreeNode copiedNode; - - public PasteNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node, - @NotNull final TreeNode copiedNode) { - super(nodeTree, node); - this.copiedNode = copiedNode; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_PASTE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PASTE_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); - final TreeNode node = getNode(); - node.accept(changeConsumer, copiedNode.getElement(), true); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java deleted file mode 100644 index 42f94151..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.RemoveControlOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The implementation of the {@link AbstractNodeAction} to remove a control from a {@link Spatial}. - * - * @author JavaSaBr - */ -public class RemoveControlAction extends AbstractNodeAction { - - public RemoveControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - final Object element = node.getElement(); - - if (!(element instanceof Control)) return; - final Control control = (Control) element; - - final TreeNode parentNode = node.getParent(); - - if (parentNode == null) { - LOGGER.warning("not found parent node for " + node); - return; - } - - final Object parent = parentNode.getElement(); - - final NodeTree nodeTree = getNodeTree(); - final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveControlOperation(control, (Spatial) parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java deleted file mode 100644 index 17a07391..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.light.Light; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.RemoveLightOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to remove a light. - * - * @author JavaSaBr - */ -public class RemoveLightAction extends AbstractNodeAction { - - public RemoveLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - final Object element = node.getElement(); - - if (!(element instanceof Light)) return; - - final Light light = (Light) element; - - final NodeTree nodeTree = getNodeTree(); - final TreeNode parentNode = nodeTree.findParent(node); - if (parentNode == null) return; - - final Object parent = parentNode.getElement(); - if (!(parent instanceof Node)) return; - - final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveLightOperation(light, (Node) parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java deleted file mode 100644 index c0ef1371..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.RemoveChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to remove a node from model. - * - * @author JavaSaBr - */ -public class RemoveNodeAction extends AbstractNodeAction { - - public RemoveNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - final Object element = node.getElement(); - if (!(element instanceof Spatial)) { - return; - } - - final Spatial spatial = (Spatial) element; - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveChildOperation(spatial, spatial.getParent())); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RenameNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RenameNodeAction.java deleted file mode 100644 index af0872c0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RenameNodeAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to rename a model node. - * - * @author JavaSaBr - */ -public class RenameNodeAction extends AbstractNodeAction { - - public RenameNodeAction(@NotNull final NodeTree nodeTree, @NotNull TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.EDIT_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_RENAME; - } - - @Override - @FxThread - protected void process() { - super.process(); - final NodeTree nodeTree = getNodeTree(); - nodeTree.startEdit(getNode()); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/SaveAsMaterialAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/SaveAsMaterialAction.java deleted file mode 100644 index 4d588e15..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/SaveAsMaterialAction.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.nio.file.StandardOpenOption.*; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.jme3.material.Material; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.util.MaterialSerializer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; -import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.function.Predicate; - -/** - * The implementation of the {@link AbstractNodeAction} to save a material as file. - * - * @author JavaSaBr - */ -public class SaveAsMaterialAction extends AbstractNodeAction { - - @NotNull - private static final Predicate> ACTION_TESTER = type -> type == NewFileAction.class || - type == DeleteFileAction.class || - type == RenameFileAction.class; - - public SaveAsMaterialAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.SAVE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_SAVE_AS; - } - - @Override - @FxThread - protected void process() { - super.process(); - UiUtils.openSaveAsDialog(this::processSave, FileExtensions.JME_MATERIAL, ACTION_TESTER); - } - - /** - * The process of saving the file. - * - * @param file the file to save - */ - @FxThread - private void processSave(@NotNull final Path file) { - - final TreeNode node = getNode(); - final Material material = (Material) node.getElement(); - final String materialContent = MaterialSerializer.serializeToString(material); - - try (final PrintWriter out = new PrintWriter(Files.newOutputStream(file, WRITE, TRUNCATE_EXISTING, CREATE))) { - out.print(materialContent); - } catch (final IOException e) { - EditorUtil.handleException(LOGGER, this, e); - return; - } - - final Path assetFile = notNull(getAssetFile(file)); - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material savedMaterial = assetManager.loadMaterial(notNull(toAssetPath(assetFile))); - - final PropertyOperation operation = - new PropertyOperation<>(material, "AssetKey", savedMaterial.getKey(), null); - operation.setApplyHandler(Material::setKey); - - final ChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); - changeConsumer.execute(operation); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/TangentGeneratorAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/TangentGeneratorAction.java deleted file mode 100644 index 455fc4cd..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/TangentGeneratorAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.dialog.GenerateTangentsDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action for generating tangents. - * - * @author JavaSaBr - */ -public class TangentGeneratorAction extends AbstractNodeAction { - - public TangentGeneratorAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_TANGENT_GENERATOR; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - final GenerateTangentsDialog dialog = new GenerateTangentsDialog(getNodeTree(), getNode()); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java deleted file mode 100644 index 15fb8e2c..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/ManualExtractSubAnimationAction.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.dialog.animation.ExtractSubAnimationDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to manual extract a sub-animation from an animation. - * - * @author JavaSaBr - */ -public class ManualExtractSubAnimationAction extends AbstractNodeAction { - - public ManualExtractSubAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_MANUAL_EXTRACT_SUB_ANIMATION; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.EXTRACT_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - final NodeTree nodeTree = getNodeTree(); - final ExtractSubAnimationDialog dialog = new ExtractSubAnimationDialog(nodeTree, (AnimationTreeNode) getNode()); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PauseAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PauseAnimationAction.java deleted file mode 100644 index c956e5b6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PauseAnimationAction.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import com.jme3.animation.AnimChannel; -import com.jme3.animation.AnimControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to pause an animation. - * - * @author JavaSaBr - */ -public class PauseAnimationAction extends AbstractNodeAction { - - public PauseAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PAUSE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PAUSE_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AnimationTreeNode modelNode = (AnimationTreeNode) getNode(); - if (modelNode.getChannel() < 0) return; - - final AnimControl control = modelNode.getControl(); - if (control == null || control.getNumChannels() <= 0) return; - - final AnimChannel channel = control.getChannel(modelNode.getChannel()); - channel.setSpeed(0); - modelNode.setSpeed(0); - - final NodeTree nodeTree = getNodeTree(); - nodeTree.update(modelNode); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlayAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlayAnimationAction.java deleted file mode 100644 index 92d2bcb5..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlayAnimationAction.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import com.jme3.animation.*; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to play an animation. - * - * @author JavaSaBr - */ -public class PlayAnimationAction extends AbstractNodeAction implements AnimEventListener { - - public PlayAnimationAction(final NodeTree nodeTree, final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PLAY; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PLAY_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AnimationTreeNode modelNode = (AnimationTreeNode) getNode(); - final AnimationControlTreeNode controlModelNode = modelNode.getControlModelNode(); - if (controlModelNode == null) return; - - final Animation element = modelNode.getElement(); - final AnimControl control = modelNode.getControl(); - if (control == null) return; - - modelNode.setSpeed(controlModelNode.getSpeed()); - - if (modelNode.getChannel() >= 0) { - final AnimChannel channel = control.getChannel(modelNode.getChannel()); - channel.setSpeed(controlModelNode.getSpeed()); - } else { - - modelNode.setChannel(control.getNumChannels()); - - EXECUTOR_MANAGER.addJmeTask(() -> { - control.addListener(this); - - final AnimChannel channel = control.createChannel(); - channel.setAnim(element.getName()); - channel.setLoopMode(controlModelNode.getLoopMode()); - channel.setSpeed(controlModelNode.getSpeed()); - }); - } - - final NodeTree nodeTree = getNodeTree(); - nodeTree.update(modelNode); - } - - @Override - @JmeThread - public void onAnimCycleDone(@NotNull final AnimControl control, @NotNull final AnimChannel channel, - @NotNull final String animName) { - - if (channel.getLoopMode() != LoopMode.DontLoop) return; - - final AnimationTreeNode modelNode = (AnimationTreeNode) getNode(); - final Animation element = modelNode.getElement(); - if (!StringUtils.equals(element.getName(), animName)) return; - - modelNode.setChannel(-1); - - EXECUTOR_MANAGER.addFxTask(() -> getNodeTree().update(modelNode)); - EXECUTOR_MANAGER.addJmeTask(control::clearChannels); - } - - @Override - @JmeThread - public void onAnimChange(@NotNull final AnimControl control, @NotNull final AnimChannel channel, - @NotNull final String animName) { - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlaySettingsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlaySettingsAction.java deleted file mode 100644 index 6ca266c3..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/PlaySettingsAction.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import static com.ss.editor.extension.property.EditablePropertyType.ENUM; -import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; -import com.jme3.animation.LoopMode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationControlTreeNode; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to open play settings of an animation. - * - * @author JavaSaBr - */ -public class PlaySettingsAction extends AbstractNodeAction { - - @NotNull - private static final String PROPERTY_LOOP_MODE = "loopMode"; - - @NotNull - private static final String PROPERTY_SPEED = "speed"; - - public PlaySettingsAction(@NotNull final NodeTree nodeTree, @NotNull final AnimationControlTreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_PLAY_SETTINGS; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.SETTINGS_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AnimationControlTreeNode node = (AnimationControlTreeNode) getNode(); - final LoopMode loopMode = node.getLoopMode(); - final float speed = node.getSpeed(); - - final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); - definitions.add(new PropertyDefinition(ENUM, Messages.MODEL_PROPERTY_LOOP_MODE, PROPERTY_LOOP_MODE, loopMode)); - definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_SPEED, PROPERTY_SPEED, speed)); - - final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, vars -> - node.updateSettings(vars.get(PROPERTY_LOOP_MODE), vars.get(PROPERTY_SPEED))); - - dialog.setTitle(Messages.PLAY_ANIMATION_SETTINGS_DIALOG_TITLE); - dialog.setButtonOkText(Messages.SIMPLE_DIALOG_BUTTON_OK); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java deleted file mode 100644 index 6760d9fa..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.animation.RemoveAnimationNodeOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link AbstractNodeAction} to remove an animation from the {@link AnimControl}. - * - * @author JavaSaBr - */ -public class RemoveAnimationAction extends AbstractNodeAction { - - public RemoveAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode node = getNode(); - final Object element = node.getElement(); - - if (!(element instanceof Animation)) return; - final Animation animation = (Animation) element; - - final NodeTree nodeTree = getNodeTree(); - final TreeNode parentNode = nodeTree.findParent(node); - - if (parentNode == null) { - LOGGER.warning("not found parent node for " + node); - return; - } - - final AnimControl parent = (AnimControl) parentNode.getElement(); - - final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveAnimationNodeOperation(animation, parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/StopAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/StopAnimationAction.java deleted file mode 100644 index 2a85ca31..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/StopAnimationAction.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.animation; - -import com.jme3.animation.AnimChannel; -import com.jme3.animation.AnimControl; -import com.jme3.animation.LoopMode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to stop an animation. - * - * @author JavaSaBr - */ -public class StopAnimationAction extends AbstractNodeAction { - - public StopAnimationAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ANIMATION_STOP; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.STOP_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AnimationTreeNode modelNode = (AnimationTreeNode) getNode(); - if (modelNode.getChannel() < 0) return; - - final AnimControl control = modelNode.getControl(); - if (control == null || control.getNumChannels() <= 0) return; - - final AnimChannel channel = control.getChannel(modelNode.getChannel()); - channel.setLoopMode(LoopMode.DontLoop); - - EXECUTOR_MANAGER.addJmeTask(control::clearChannels); - - final NodeTree nodeTree = getNodeTree(); - nodeTree.update(modelNode); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java deleted file mode 100644 index a27293fc..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.audio; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.audio.AudioNode; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create an audio node. - * - * @author JavaSaBr - */ -public class CreateAudioNodeAction extends AbstractNodeAction { - - public CreateAudioNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.AUDIO_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_AUDIO_NODE; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - - final AudioNode node = new AudioNode(); - node.setName("New audio"); - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new AddChildOperation(node, parent)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/PlayAudioNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/PlayAudioNodeAction.java deleted file mode 100644 index 26044404..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/PlayAudioNodeAction.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.audio; - -import com.jme3.asset.AssetManager; -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioNode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.AudioTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.AudioNodeUtils; -import com.ss.editor.util.EditorUtil; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to play an audio node. - * - * @author JavaSaBr - */ -public class PlayAudioNodeAction extends AbstractNodeAction { - - public PlayAudioNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PLAY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_AUDIO_PLAY; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AudioTreeNode audioModelNode = (AudioTreeNode) getNode(); - final AudioNode audioNode = audioModelNode.getElement(); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - - EXECUTOR_MANAGER.addJmeTask(() -> { - - final AudioKey audioKey = AudioNodeUtils.getAudioKey(audioNode); - final AudioData audioData = assetManager.loadAudio(audioKey); - - AudioNodeUtils.updateData(audioNode, audioData, audioKey); - - audioNode.play(); - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/StopAudioNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/StopAudioNodeAction.java deleted file mode 100644 index 42a420f1..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/StopAudioNodeAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.audio; - -import com.jme3.audio.AudioNode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.AudioTreeNode; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to stop an audio node. - * - * @author JavaSaBr - */ -public class StopAudioNodeAction extends AbstractNodeAction { - - public StopAudioNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.STOP_16; - } - - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_AUDIO_STOP; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final AudioTreeNode audioModelNode = (AudioTreeNode) getNode(); - final AudioNode audioNode = audioModelNode.getElement(); - - EXECUTOR_MANAGER.addJmeTask(audioNode::stop); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java deleted file mode 100644 index 84da4962..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddControlOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create the {@link Control}. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateControlAction extends AbstractNodeAction { - - public AbstractCreateControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected void process() { - super.process(); - - if (isRequiredDialog()) { - return; - } - - final TreeNode treeNode = getNode(); - final Spatial parent = (Spatial) treeNode.getElement(); - - final NodeTree nodeTree = getNodeTree(); - final Control control = createControl(parent); - - final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - consumer.execute(new AddControlOperation(control, parent)); - } - - /** - * Return true if need a dialog to create a control. - * - * @return true if need a dialog to create a control. - */ - @FxThread - protected boolean isRequiredDialog() { - return false; - } - - /** - * Create a control. - * - * @param parent the parent. - * @return the control. - */ - @FxThread - protected @NotNull Control createControl(@NotNull final Spatial parent) { - throw new UnsupportedOperationException(); - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateCustomControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateCustomControlAction.java deleted file mode 100644 index 03d93ed7..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateCustomControlAction.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.dialog.CreateCustomControlDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link Control}. - * - * @author JavaSaBr - */ -public class CreateCustomControlAction extends AbstractNodeAction { - - /** - * Instantiates a new Create custom control action. - * - * @param nodeTree the node tree - * @param node the node - */ - public CreateCustomControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @FxThread - @Nullable - @Override - protected Image getIcon() { - return Icons.GEAR_16; - } - - @FxThread - @NotNull - @Override - protected String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_CUSTOM; - } - - @FxThread - @Override - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - - final TreeNode treeNode = getNode(); - final Spatial parent = (Spatial) treeNode.getElement(); - - final CreateCustomControlDialog dialog = new CreateCustomControlDialog(consumer, parent); - dialog.show(); - } -} \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateLightControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateLightControlAction.java deleted file mode 100644 index 23a0bdcd..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/CreateLightControlAction.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control; - -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.jme3.scene.control.LightControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link com.jme3.scene.control.LightControl}. - * - * @author JavaSaBr - */ -public class CreateLightControlAction extends AbstractCreateControlAction { - - public CreateLightControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.LIGHT_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_LIGHT; - } - - @Override - @FxThread - protected @NotNull Control createControl(@NotNull final Spatial parent) { - return new LightControl(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java deleted file mode 100644 index 69a6a549..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics; - -import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.control.BetterCharacterControl; -import com.jme3.bullet.control.CharacterControl; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddControlOperation; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link CharacterControl}. - * - * @author JavaSaBr - */ -public class CreateCharacterControlAction extends AbstractCreateControlAction { - - private static final String PROPERTY_RADIUS = "radius"; - private static final String PROPERTY_HEIGHT = "height"; - private static final String PROPERTY_MASS = "mass"; - - public CreateCharacterControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.CHARACTER_16; - } - - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_CHARACTER; - } - - @Override - protected void process() { - - final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); - definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_RADIUS, PROPERTY_RADIUS, 1F)); - definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_HEIGHT, PROPERTY_HEIGHT, 1F)); - definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_MASS, PROPERTY_MASS, 1F)); - - final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, vars -> { - - final float radius = vars.getFloat(PROPERTY_RADIUS); - final float height = vars.getFloat(PROPERTY_HEIGHT); - final float mass = vars.getFloat(PROPERTY_MASS); - - final TreeNode treeNode = getNode(); - final Spatial parent = (Spatial) treeNode.getElement(); - - final NodeTree nodeTree = getNodeTree(); - final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - consumer.execute(new AddControlOperation(new BetterCharacterControl(radius, height, mass), parent)); - }); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java deleted file mode 100644 index 310949f4..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateKinematicRagdollControlAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics; - -import com.jme3.bullet.control.KinematicRagdollControl; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link KinematicRagdollControl}. - * - * @author JavaSaBr - */ -public class CreateKinematicRagdollControlAction extends AbstractCreateControlAction { - - public CreateKinematicRagdollControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @FxThread - @Override - protected @Nullable Image getIcon() { - return Icons.ATOM_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_KINEMATIC_RAGDOLL; - } - - @Override - @FxThread - protected @NotNull Control createControl(@NotNull final Spatial parent) { - return new KinematicRagdollControl(0.5F); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java deleted file mode 100644 index 9cbc300c..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics; - -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.ControlUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link RigidBodyControl}. - * - * @author JavaSaBr - */ -public class CreateRigidBodyControlAction extends AbstractCreateControlAction { - - public CreateRigidBodyControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.RIGID_BODY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_RIGID_BODY; - } - - @Override - @FxThread - protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { - final RigidBodyControl rigidBodyControl = new RigidBodyControl(); - rigidBodyControl.setEnabled(false); - ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); - return rigidBodyControl; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java deleted file mode 100644 index 4cafe118..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics; - -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.ControlUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link RigidBodyControl}. - * - * @author JavaSaBr - */ -public class CreateStaticRigidBodyControlAction extends CreateRigidBodyControlAction { - - public CreateStaticRigidBodyControlAction(@NotNull final NodeTree nodeTree, - @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.STATIC_RIGID_BODY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_STATIC_RIGID_BODY; - } - - @Override - @FxThread - protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { - final RigidBodyControl rigidBodyControl = new RigidBodyControl(); - rigidBodyControl.setEnabled(false); - rigidBodyControl.setMass(0F); - ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); - return rigidBodyControl; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java deleted file mode 100644 index 676cd489..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics; - -import com.jme3.bullet.control.RigidBodyControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to re-activate a physics control. - * - * @author JavaSaBr - */ -public class ReactivatePhysicsControlAction extends AbstractNodeAction { - - public ReactivatePhysicsControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REPLAY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REACTIVATE; - } - - @Override - @FxThread - protected void process() { - - final Object element = getNode().getElement(); - - if (element instanceof RigidBodyControl) { - final RigidBodyControl control = (RigidBodyControl) element; - EXECUTOR_MANAGER.addJmeTask(control::activate); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java deleted file mode 100644 index fa3cf891..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleControlAction.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle; - -import com.jme3.bullet.collision.shapes.BoxCollisionShape; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.math.Vector3f; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link VehicleControl}. - * - * @author JavaSaBr - */ -public class CreateVehicleControlAction extends AbstractCreateControlAction { - - public CreateVehicleControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.VEHICLE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_VEHICLE; - } - - @Override - @FxThread - protected @NotNull Control createControl(@NotNull final Spatial parent) { - return new VehicleControl(new BoxCollisionShape(new Vector3f(1F, 1F, 1F)), 1F); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java deleted file mode 100644 index b89e6e04..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.bullet.objects.VehicleWheel; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.RemoveVehicleWheelOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to remove a vehicle wheel from a control. - * - * @author JavaSaBr - */ -public class RemoveVehicleWheelAction extends AbstractNodeAction { - - public RemoveVehicleWheelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected void process() { - - final TreeNode node = getNode(); - final Object element = node.getElement(); - final TreeNode nodeParent = notNull(node.getParent()); - final VehicleControl vehicleControl = (VehicleControl) nodeParent.getElement(); - final VehicleWheel vehicleWheel = (VehicleWheel) element; - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveVehicleWheelOperation(vehicleControl, vehicleWheel)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java deleted file mode 100644 index 8a553fd0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.geometry; - -import static com.ss.editor.util.EditorUtil.getDefaultLayer; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.material.Material; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create the {@link Geometry}. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateGeometryAction extends AbstractNodeAction { - - public AbstractCreateGeometryAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - final SceneLayer defaultLayer = getDefaultLayer(consumer); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Geometry geometry = createGeometry(); - geometry.setMaterial(new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md")); - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, geometry); - } - - consumer.execute(new AddChildOperation(geometry, parent)); - } - - /** - * Create geometry geometry. - * - * @return the geometry - */ - @FxThread - protected abstract @NotNull Geometry createGeometry(); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateBoxAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateBoxAction.java deleted file mode 100644 index 02739dab..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateBoxAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.geometry; - -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Box; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create a {@link Geometry} with a {@link Box} mesh. - * - * @author JavaSaBr - */ -public class CreateBoxAction extends AbstractCreateGeometryAction { - - public CreateBoxAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.CUBE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_BOX; - } - - @Override - @FxThread - protected @NotNull Geometry createGeometry() { - return new Geometry("Box", new Box(1, 1, 1)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateQuadAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateQuadAction.java deleted file mode 100644 index 01a4162f..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateQuadAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.geometry; - -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Quad; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create a {@link Geometry} with a {@link Quad} mesh. - * - * @author JavaSaBr - */ -public class CreateQuadAction extends AbstractCreateGeometryAction { - - public CreateQuadAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.PLANE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_QUAD; - } - - @Override - @FxThread - protected @NotNull Geometry createGeometry() { - return new Geometry("Quad", new Quad(2, 2)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateSphereAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateSphereAction.java deleted file mode 100644 index f252f9dd..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/CreateSphereAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.geometry; - -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Sphere; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create a {@link Geometry} with a {@link Sphere} mesh. - * - * @author JavaSaBr - */ -public class CreateSphereAction extends AbstractCreateGeometryAction { - - public CreateSphereAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.SPHERE_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE_SPHERE; - } - - @Override - @FxThread - protected @NotNull Geometry createGeometry() { - return new Geometry("Sphere", new Sphere(30, 30, 1)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/GenerateLoDAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/GenerateLoDAction.java deleted file mode 100644 index 6a7d4643..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/GenerateLoDAction.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.geometry; - -import com.jme3.scene.Geometry; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.GeometryTreeNode; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.dialog.geometry.lod.GenerateLodLevelsDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.ClassUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to generate levels of details for the geometry. - * - * @author JavaSaBr - */ -public class GenerateLoDAction extends AbstractNodeAction { - - public GenerateLoDAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_LOD_GENERATOR; - } - - @Override - @FxThread - protected void process() { - final GeometryTreeNode modelNode = ClassUtils.unsafeCast(getNode()); - final Geometry geometry = modelNode.getElement(); - final GenerateLodLevelsDialog dialog = new GenerateLodLevelsDialog(getNodeTree(), geometry); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java deleted file mode 100644 index f61368a0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.light; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.light.Light; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.impl.AddLightOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create a {@link Light}. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateLightAction extends AbstractNodeAction { - - public AbstractCreateLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - - final Light light = createLight(); - if (light.getName() == null) { - light.setName(""); - } - - final TreeNode treeNode = getNode(); - final Node element = (Node) treeNode.getElement(); - - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new AddLightOperation(light, element)); - } - - /** - * Create light light. - * - * @return the light - */ - @FxThread - protected abstract @NotNull Light createLight(); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateAmbientLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateAmbientLightAction.java deleted file mode 100644 index 0b4cda51..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateAmbientLightAction.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.light; - -import com.jme3.light.AmbientLight; -import com.jme3.light.Light; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create an {@link AmbientLight}. - * - * @author JavaSaBr - */ -public class CreateAmbientLightAction extends AbstractCreateLightAction { - - public CreateAmbientLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.AMBIENT_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_AMBIENT_LIGHT; - } - - @Override - @FxThread - protected @NotNull Light createLight() { - final AmbientLight ambientLight = new AmbientLight(); - ambientLight.setName(Messages.MODEL_NODE_TREE_ACTION_AMBIENT_LIGHT); - return ambientLight; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateDirectionLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateDirectionLightAction.java deleted file mode 100644 index 9cb4280a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateDirectionLightAction.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.light; - -import com.jme3.light.DirectionalLight; -import com.jme3.light.Light; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create a {@link DirectionalLight}. - * - * @author JavaSaBr - */ -public class CreateDirectionLightAction extends AbstractCreateLightAction { - - public CreateDirectionLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.SUN_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_DIRECTION_LIGHT; - } - - @Override - @FxThread - protected @NotNull Light createLight() { - final DirectionalLight directionalLight = new DirectionalLight(); - directionalLight.setName(Messages.MODEL_NODE_TREE_ACTION_DIRECTION_LIGHT); - return directionalLight; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreatePointLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreatePointLightAction.java deleted file mode 100644 index aa9fc8a8..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreatePointLightAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.light; - -import com.jme3.light.Light; -import com.jme3.light.PointLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link PointLight}. - * - * @author JavaSaBr - */ -public class CreatePointLightAction extends AbstractCreateLightAction { - - public CreatePointLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.POINT_LIGHT_16; - } - - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_POINT_LIGHT; - } - - @Override - @FxThread - protected @NotNull Light createLight() { - final PointLight pointLight = new PointLight(); - pointLight.setName(Messages.MODEL_NODE_TREE_ACTION_POINT_LIGHT); - return pointLight; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateSpotLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateSpotLightAction.java deleted file mode 100644 index bfbc4fb3..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/CreateSpotLightAction.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.light; - -import com.jme3.light.Light; -import com.jme3.light.SpotLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; - -/** - * The action to create a {@link SpotLight}. - * - * @author JavaSaBr - */ -public class CreateSpotLightAction extends AbstractCreateLightAction { - - public CreateSpotLightAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.LAMP_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_SPOT_LIGHT; - } - - @Override - @FxThread - protected @NotNull Light createLight() { - final SpotLight spotLight = new SpotLight(); - spotLight.setName(Messages.MODEL_NODE_TREE_ACTION_SPOT_LIGHT); - return spotLight; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java deleted file mode 100644 index b67c89b4..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.multi; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.RemoveElementsOperation; -import com.ss.editor.model.undo.impl.RemoveElementsOperation.Element; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; -import com.ss.editor.ui.control.tree.node.impl.light.LightTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.SpatialTreeNode; -import com.ss.rlib.common.function.TripleConsumer; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayCollectors; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The action to remove some elements from a scene/model. - * - * @author JavaSaBr - */ -public class RemoveElementsAction extends AbstractNodeAction { - - private static final Array> AVAILABLE_TYPES = ArrayFactory.newArray(Class.class); - - static { - AVAILABLE_TYPES.add(SpatialTreeNode.class); - AVAILABLE_TYPES.add(ControlTreeNode.class); - AVAILABLE_TYPES.add(LightTreeNode.class); - AVAILABLE_TYPES.add(AnimationTreeNode.class); - } - - public static final TripleConsumer, List, Array>> ACTION_FILLER = (nodeTree, menuItems, treeNodes) -> { - - final TreeNode unexpectedItem = treeNodes.search(treeNode -> - AVAILABLE_TYPES.search(treeNode, Class::isInstance) == null || !treeNode.canRemove()); - - if (unexpectedItem == null) { - menuItems.add(new RemoveElementsAction(nodeTree, treeNodes)); - } - }; - - public RemoveElementsAction(@NotNull final NodeTree nodeTree, @NotNull final Array> nodes) { - super(nodeTree, nodes); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - public void process() { - super.process(); - - final Array> nodes = getNodes(); - final Array toRemove = nodes.stream() - .filter(treeNode -> treeNode.getParent() != null) - .map(this::convert) - .collect(ArrayCollectors.toArray(Element.class)); - - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RemoveElementsOperation(toRemove)); - } - - @FxThread - private @NotNull Element convert(@NotNull final TreeNode treeNode) { - final Object value = treeNode.getElement(); - final TreeNode parentNode = notNull(treeNode.getParent()); - final Object parent = parentNode.getElement(); - return new Element(value, parent); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java deleted file mode 100644 index 00006d1a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter; - -import static com.ss.editor.util.EditorUtil.getDefaultLayer; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.ParticleMesh; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.EditorUtil; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action for creating new {@link ParticleEmitter}. - * - * @author JavaSaBr - */ -public class CreateParticleEmitterAction extends AbstractNodeAction { - - public CreateParticleEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.EMITTER_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_DEFAULT_PARTICLE_EMITTER; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - final SceneLayer defaultLayer = getDefaultLayer(changeConsumer); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Material material = new Material(assetManager,"Common/MatDefs/Misc/Particle.j3md"); - material.setTexture("Texture", assetManager.loadTexture( "Effects/Explosion/flame.png")); - - final ParticleEmitter emitter = createParticleEmitter(); - emitter.setMaterial(material); - emitter.setImagesX(2); - emitter.setImagesY(2); // 2x2 texture animation - emitter.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red - emitter.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow - emitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0)); - emitter.setStartSize(1.5f); - emitter.setEndSize(0.1f); - emitter.setGravity(0, 0, 0); - emitter.setLowLife(1f); - emitter.setHighLife(3f); - emitter.getParticleInfluencer().setVelocityVariation(0.3f); - emitter.setEnabled(true); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, emitter); - } - - final TreeNode treeNode = getNode(); - final Node parent = (Node) treeNode.getElement(); - - changeConsumer.execute(new AddChildOperation(emitter, parent)); - } - - @FxThread - protected @NotNull ParticleEmitter createParticleEmitter() { - return new ParticleEmitter("Default Emitter", ParticleMesh.Type.Triangle, 30); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java deleted file mode 100644 index 55593102..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/ResetParticleEmittersAction.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter; - -import static com.ss.editor.util.NodeUtils.visitSpatial; -import com.jme3.effect.ParticleEmitter; -import com.jme3.scene.Node; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Function; - -/** - * The action to reset a {@link ParticleEmitter}. - * - * @author JavaSaBr - */ -public class ResetParticleEmittersAction extends AbstractNodeAction { - - /** - * The list of additional action on executing this action. - */ - @NotNull - private static final Array> ADDITIONAL_ACTIONS = ArrayFactory.newArray(Function.class); - - /** - * Register the additional action on executing this action. - * - * @param action the additional action on executing this action. - */ - @FxThread - public static void registerAdditionalAction(@NotNull final Function<@NotNull Node, @Nullable Runnable> action) { - ADDITIONAL_ACTIONS.add(action); - } - - public ResetParticleEmittersAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REPLAY_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_RESET_PARTICLE_EMITTERS; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final TreeNode treeNode = getNode(); - final Node node = (Node) treeNode.getElement(); - - EXECUTOR_MANAGER.addJmeTask(() -> visitSpatial(node, ParticleEmitter.class, ParticleEmitter::killAllParticles)); - ADDITIONAL_ACTIONS.forEach(node, (factory, toCheck) -> { - final Runnable action = factory.apply(toCheck); - if (action != null) { - EXECUTOR_MANAGER.addJmeTask(action); - } - }); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java deleted file mode 100644 index 4be166b5..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.emitter.ChangeParticleInfluencerOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a {@link ParticleInfluencer} for a {@link ParticleEmitter}. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateParticleInfluencerAction extends AbstractNodeAction { - - public AbstractCreateParticleInfluencerAction(@NotNull final NodeTree nodeTree, - @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.INFLUENCER_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final ModelChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - - final TreeNode treeNode = getNode(); - final ParticleEmitter emitter = (ParticleEmitter) treeNode.getElement(); - final ParticleInfluencer influencer = createInfluencer(); - - changeConsumer.execute(new ChangeParticleInfluencerOperation(influencer, emitter)); - } - - /** - * Create influencer particle influencer. - * - * @return the particle influencer - */ - @FxThread - protected abstract @NotNull ParticleInfluencer createInfluencer(); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java deleted file mode 100644 index 23f77df6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateDefaultParticleInfluencerAction.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer; - -import com.jme3.effect.influencers.DefaultParticleInfluencer; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create an {@link DefaultParticleInfluencer}. - * - * @author JavaSaBr - */ -public class CreateDefaultParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { - - public CreateDefaultParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull ParticleInfluencer createInfluencer() { - return new DefaultParticleInfluencer(); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_DEFAULT; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java deleted file mode 100644 index cab715c0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateEmptyParticleInfluencerAction.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer; - -import com.jme3.effect.influencers.EmptyParticleInfluencer; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create an {@link EmptyParticleInfluencer}. - * - * @author JavaSaBr - */ -public class CreateEmptyParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { - - public CreateEmptyParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull ParticleInfluencer createInfluencer() { - return new EmptyParticleInfluencer(); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_EMPTY; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java deleted file mode 100644 index 4ff1d07b..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/CreateRadialParticleInfluencerAction.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer; - -import com.jme3.effect.influencers.EmptyParticleInfluencer; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.jme3.effect.influencers.RadialParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The action to create an {@link EmptyParticleInfluencer}. - * - * @author JavaSaBr - */ -public class CreateRadialParticleInfluencerAction extends AbstractCreateParticleInfluencerAction { - - public CreateRadialParticleInfluencerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull ParticleInfluencer createInfluencer() { - return new RadialParticleInfluencer(); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_INFLUENCER_RADIAL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java deleted file mode 100644 index 321ed491..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.shapes.EmitterShape; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.emitter.ChangeEmitterShapeOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; - -/** - * The action to switch an {@link EmitterShape} of the {@link ParticleEmitter}. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateShapeEmitterAction extends AbstractNodeAction { - - public AbstractCreateShapeEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.GEOMETRY_16; - } - - @FxThread - @Override - protected void process() { - super.process(); - - final Point dialogSize = getDialogSize(); - - final GenericFactoryDialog dialog = new GenericFactoryDialog(getPropertyDefinitions(), this::handleResult); - dialog.setTitle(getDialogTitle()); - - if (dialogSize != null) { - dialog.updateSize(dialogSize); - } - - dialog.show(); - } - - /** - * Gets another dialog size. - * - * @return the dialog size or null. - */ - @FxThread - protected @Nullable Point getDialogSize() { - return null; - } - - /** - * Gets a dialog title. - * - * @return the dialog title. - */ - @FxThread - protected abstract @NotNull String getDialogTitle(); - - /** - * Handle the result from the dialog. - * - * @param vars the table with variables. - */ - @FxThread - private void handleResult(@NotNull final VarTable vars) { - - final TreeNode treeNode = getNode(); - final ParticleEmitter element = (ParticleEmitter) treeNode.getElement(); - final EmitterShape emitterShape = createEmitterShape(vars); - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new ChangeEmitterShapeOperation(emitterShape, element)); - } - - /** - * Gets a list of property definitions to create a shape. - * - * @return the list of definitions. - */ - @FxThread - protected abstract @NotNull Array getPropertyDefinitions(); - - /** - * Create emitter shape. - * - * @param vars the table with variables. - * @return the emitter shape. - */ - @FxThread - protected abstract @NotNull EmitterShape createEmitterShape(@NotNull final VarTable vars); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java deleted file mode 100644 index 34e70d08..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/CreateMeshFaceShapeEmitterAction.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape; - -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.shapes.EmitterMeshFaceShape; -import com.jme3.effect.shapes.EmitterMeshVertexShape; -import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * The action to create a {@link EmitterMeshFaceShape} to the {@link ParticleEmitter}. - * - * @author JavaSaBr - */ -public class CreateMeshFaceShapeEmitterAction extends CreateMeshVertexShapeEmitterAction { - - public CreateMeshFaceShapeEmitterAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @NotNull EmitterMeshVertexShape createEmitterShape(@NotNull final List meshes) { - return new EmitterMeshFaceShape(meshes); - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_MESH_FACE_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java deleted file mode 100644 index da69e460..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.physics.shape; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.collision.PhysicsCollisionObject; -import com.jme3.bullet.collision.shapes.CollisionShape; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.undo.impl.ChangeCollisionShapeOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a new shape. - * - * @author JavaSaBr - */ -public abstract class AbstractCreateShapeAction extends AbstractNodeAction { - - AbstractCreateShapeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.GEOMETRY_16; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final Array definitions = getPropertyDefinitions(); - if (definitions.isEmpty()) return; - - final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, this::handleResult); - dialog.setTitle(getDialogTitle()); - dialog.show(); - } - - /** - * Gets a dialog title. - * - * @return the dialog title. - */ - @FxThread - protected abstract @NotNull String getDialogTitle(); - - /** - * Handle the result from the dialog. - * - * @param vars the table with variables. - */ - @FxThread - private void handleResult(@NotNull final VarTable vars) { - - final TreeNode treeNode = getNode(); - final PhysicsCollisionObject element = (PhysicsCollisionObject) treeNode.getElement(); - final CollisionShape shape = createShape(vars); - final CollisionShape currentShape = element.getCollisionShape(); - - final NodeTree nodeTree = getNodeTree(); - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new ChangeCollisionShapeOperation(shape, currentShape, element)); - } - - /** - * Gets a list of property definitions to create a shape. - * - * @return the list of definitions. - */ - @FxThread - protected abstract @NotNull Array getPropertyDefinitions(); - - /** - * Create a collision shape. - * - * @param vars the table with variables. - * @return the collision shape - */ - @FxThread - protected abstract @NotNull CollisionShape createShape(@NotNull final VarTable vars); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java deleted file mode 100644 index 3c285a47..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.scene; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.ui.control.tree.node.impl.layer.LayersRootTreeNode; -import com.ss.editor.model.undo.impl.scene.AddSceneLayerOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create a scene layer. - * - * @author JavaSaBr - */ -public class CreateSceneLayerAction extends AbstractNodeAction { - - public CreateSceneLayerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.LAYERS_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_CREATE_LAYER; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final SceneLayer layer = new SceneLayer("New Layer", false); - final LayersRootTreeNode modelNode = (LayersRootTreeNode) getNode(); - final LayersRoot element = modelNode.getElement(); - final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); - final SceneNode sceneNode = changeConsumer.getCurrentModel(); - - changeConsumer.execute(new AddSceneLayerOperation(element, layer, sceneNode)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java deleted file mode 100644 index c339d43a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.scene; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.ui.control.tree.node.impl.layer.SceneLayerTreeNode; -import com.ss.editor.model.undo.impl.scene.RemoveSceneLayerOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to remove a scene layer. - * - * @author JavaSaBr - */ -public class RemoveSceneLayerAction extends AbstractNodeAction { - - public RemoveSceneLayerAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.REMOVE_12; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_REMOVE; - } - - @Override - @FxThread - protected void process() { - super.process(); - - final NodeTree nodeTree = getNodeTree(); - final SceneChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - final SceneNode sceneNode = changeConsumer.getCurrentModel(); - - final SceneLayerTreeNode modelNode = (SceneLayerTreeNode) getNode(); - final SceneLayer layer = modelNode.getElement(); - - changeConsumer.execute(new RemoveSceneLayerOperation(new LayersRoot(changeConsumer), layer, sceneNode)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/terrain/CreateTerrainAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/terrain/CreateTerrainAction.java deleted file mode 100644 index 6f82d8f9..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/terrain/CreateTerrainAction.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.ss.editor.ui.control.tree.action.impl.terrain; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.dialog.terrain.CreateTerrainDialog; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The action to create terrain. - * - * @author JavaSaBr - */ -public class CreateTerrainAction extends AbstractNodeAction { - - public CreateTerrainAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { - super(nodeTree, node); - } - - @Override - @FxThread - protected @Nullable Image getIcon() { - return Icons.TERRAIN_16; - } - - @Override - @FxThread - protected @NotNull String getName() { - return Messages.MODEL_NODE_TREE_ACTION_ADD_TERRAIN; - } - - @Override - @FxThread - protected void process() { - super.process(); - final CreateTerrainDialog dialog = new CreateTerrainDialog(getNode(), getNodeTree()); - dialog.show(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/HideableNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/HideableNode.java deleted file mode 100644 index b2bb5f65..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/HideableNode.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.control.tree.node; - -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; - -import org.jetbrains.annotations.NotNull; - -/** - * The interface-marker that an object can be hide. - * - * @param the type parameter - * @author JavaSaBr - */ -public interface HideableNode { - - /** - * Is hided boolean. - * - * @return true if this object is hided. - */ - boolean isHided(); - - /** - * Show the object. - * - * @param nodeTree the node tree - */ - void show(@NotNull NodeTree nodeTree); - - /** - * Hide the object. - * - * @param nodeTree the node tree - */ - void hide(@NotNull NodeTree nodeTree); -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/TreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/TreeNode.java deleted file mode 100644 index e2a86af7..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/TreeNode.java +++ /dev/null @@ -1,413 +0,0 @@ -package com.ss.editor.ui.control.tree.node; - -import static com.ss.editor.ui.control.tree.NodeTreeCell.DATA_FORMAT; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.UObject; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.action.impl.CopyNodeAction; -import com.ss.editor.ui.control.tree.action.impl.PasteNodeAction; -import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactoryRegistry; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TreeItem; -import javafx.scene.image.Image; -import javafx.scene.input.Clipboard; -import javafx.scene.input.Dragboard; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.Objects; - -/** - * The base implementation of a tree node. - * - * @param the type of presented element - * @author JavaSaBr - */ -public abstract class TreeNode implements UObject { - - /** - * The constant EMPTY_ARRAY. - */ - @NotNull - protected static final Array> EMPTY_ARRAY = ArrayFactory.newArray(TreeNode.class); - - /** - * The constant FACTORY_REGISTRY. - */ - @NotNull - protected static final TreeNodeFactoryRegistry FACTORY_REGISTRY = TreeNodeFactoryRegistry.getInstance(); - - /** - * The action's comparator. - */ - @NotNull - protected static final Comparator ACTION_COMPARATOR = (first, second) -> { - if (first instanceof Menu) { - return -1; - } else if (second instanceof Menu) { - return 1; - } else if (first instanceof AbstractNodeAction) { - return ((AbstractNodeAction) first).compareTo(second); - } else { - return 0; - } - }; - - /** - * The uniq id of this node. - */ - private final long objectId; - - /** - * The wrapped element. - */ - @NotNull - private final T element; - - /** - * The parent node. - */ - @Nullable - private TreeNode parent; - - public TreeNode(@NotNull final T element, final long objectId) { - this.element = element; - this.objectId = objectId; - } - - /** - * Get the wrapped element. - * - * @return the wrapped element. - */ - @FromAnyThread - public @NotNull T getElement() { - return element; - } - - /** - * Get the name of this node. - * - * @return the name of this node. - */ - @FromAnyThread - public @NotNull String getName() { - return "unknown name"; - } - - /** - * Set the name of this node. - * - * @param name the name of this node. - */ - @FxThread - public void setName(@NotNull final String name) { - } - - /** - * Is need to save name. - * - * @return true if need to save name. - */ - @FromAnyThread - public boolean isNeedToSaveName() { - return false; - } - - /** - * Has children boolean. - * - * @param nodeTree the node tree - * @return true of this node has any children. - */ - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return false; - } - - /** - * Get the children. - * - * @param nodeTree the node tree - * @return the array of children of this node. - */ - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - return EMPTY_ARRAY; - } - - /** - * Gets parent. - * - * @return the parent of this node or null. - */ - @FxThread - public @Nullable TreeNode getParent() { - return parent; - } - - /** - * Set the parent node. - * - * @param parent the parent node. - */ - @FxThread - protected void setParent(@Nullable final TreeNode parent) { - this.parent = parent; - } - - /** - * Get the icon of this node. - * - * @return the icon of this node or null. - */ - @FxThread - public @Nullable Image getIcon() { - return null; - } - - /** - * Fill the items actions for this node. - * - * @param nodeTree the node tree - * @param items the items - */ - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - - if (canEditName()) { - items.add(new RenameNodeAction(nodeTree, this)); - } - - if (canCopy()) { - items.add(new CopyNodeAction(nodeTree, this)); - } - - final Clipboard clipboard = Clipboard.getSystemClipboard(); - final Object content = clipboard.getContent(DATA_FORMAT); - if (!(content instanceof Long)) { - return; - } - - final Long objectId = (Long) content; - final TreeItem treeItem = UiUtils.findItem(nodeTree.getTreeView(), objectId); - final TreeNode treeNode = treeItem == null ? null : (TreeNode) treeItem.getValue(); - - if (treeNode != null && canAccept(treeNode, true)) { - items.add(new PasteNodeAction(nodeTree, this, treeNode)); - } - } - - /** - * Handle the result context menu. - * - * @param nodeTree the node tree. - * @param items the result items. - */ - @FxThread - public void handleResultContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - items.sort(ACTION_COMPARATOR); - } - - /** - * Remove the child from this node. - * - * @param child the child - */ - @FxThread - public void remove(@NotNull final TreeNode child) { - } - - /** - * Add the new child to this node. - * - * @param child the child - */ - @FxThread - public void add(@NotNull final TreeNode child) { - } - - /** - * Handle changing the name of this node. - * - * @param nodeTree the node tree - * @param newName the new name - */ - @FxThread - public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - } - - /** - * Check of possibility to accept the tree node as a new child. - * - * @param treeNode the node. - * @param isCopy true if need to copy the node. - * @return true if this node can be accept. - */ - @FxThread - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - return false; - } - - /** - * Accept the object to this node. - * - * @param changeConsumer the change consumer. - * @param object the object. - * @param isCopy true if need to copy the object. - */ - @FxThread - public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, - final boolean isCopy) { - } - - /** - * Can accept external boolean. - * - * @param dragboard the dragboard - * @return true if this node can accept external resource. - */ - @FxThread - public boolean canAcceptExternal(@NotNull final Dragboard dragboard) { - return false; - } - - /** - * Accept external resources to this node. - * - * @param dragboard the dragboard - * @param consumer the consumer - */ - @FxThread - public void acceptExternal(@NotNull final Dragboard dragboard, @NotNull final ChangeConsumer consumer) { - } - - /** - * Can move boolean. - * - * @return true if this node supports moving. - */ - @FxThread - public boolean canMove() { - return false; - } - - /** - * Can copy boolean. - * - * @return true if this node supports copying. - */ - @FxThread - public boolean canCopy() { - return false; - } - - /** - * Can edit name boolean. - * - * @return true if this node supports name editing. - */ - @FxThread - public boolean canEditName() { - return false; - } - - /** - * Can remove boolean. - * - * @return true if you can remove this node. - */ - @FxThread - public boolean canRemove() { - return true; - } - - /** - * Copy model node. - * - * @return the new copy of this node. - */ - @FxThread - public @NotNull TreeNode copy() { - throw new UnsupportedOperationException(); - } - - @Override - @FromAnyThread - public long getObjectId() { - return objectId; - } - - @Override - public String toString() { - return getName(); - } - - @Override - public boolean equals(@Nullable final Object other) { - - if (this == other) return true; - if (other == null) return false; - - if (other instanceof TreeNode) { - TreeNode treeNode = (TreeNode) other; - return element.equals(treeNode.element); - } - - return Objects.equals(element, other); - } - - @Override - public int hashCode() { - return element.hashCode(); - } - - /** - * Notify about that a model node was added to children of this node. - * - * @param treeNode the model node. - */ - @FxThread - public void notifyChildAdded(@NotNull final TreeNode treeNode) { - } - - /** - * Notify about that a model node was removed from children of this node. - * - * @param treeNode the model node. - */ - @FxThread - public void notifyChildRemoved(@NotNull final TreeNode treeNode) { - treeNode.setParent(null); - } - - /** - * Notify about that a model node will add to children of this node. - * - * @param treeNode the model node. - */ - @FxThread - public void notifyChildPreAdd(@NotNull final TreeNode treeNode) { - treeNode.setParent(this); - } - - /** - * Notify about that a model node will remove from children of this node. - * - * @param treeNode the model node. - */ - @FxThread - public void notifyChildPreRemove(@NotNull final TreeNode treeNode) { - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java deleted file mode 100644 index 0fe06f9f..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.ss.editor.ui.control.tree.node.factory; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.factory.impl.MaterialSettingsTreeNodeFactory; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.impl.*; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * The registry of available tree node factories. - * - * @author JavaSaBr - */ -public class TreeNodeFactoryRegistry { - - @NotNull - private static final TreeNodeFactoryRegistry INSTANCE = new TreeNodeFactoryRegistry(); - - /** - * The node id generator. - */ - @NotNull - private static final AtomicLong ID_GENERATOR = new AtomicLong(); - - @NotNull - public static TreeNodeFactoryRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of available factories. - */ - @NotNull - private final Array factories; - - private TreeNodeFactoryRegistry() { - this.factories = ArrayFactory.newArray(TreeNodeFactory.class); - register(new PrimitiveTreeNodeFactory()); - register(new AnimationTreeNodeFactory()); - register(new CollisionTreeNodeFactory()); - register(new ControlTreeNodeFactory()); - register(new DefaultParticlesTreeNodeFactory()); - register(new DefaultTreeNodeFactory()); - register(new LightTreeNodeFactory()); - register(new MaterialSettingsTreeNodeFactory()); - } - - /** - * Register a new tree node factory. - * - * @param factory the tree node factory. - */ - @FxThread - public void register(@NotNull final TreeNodeFactory factory) { - this.factories.add(factory); - this.factories.sort(TreeNodeFactory::compareTo); - } - - /** - * Get all available tree node factories. - * - * @return the list of available tree node factories. - */ - @FxThread - private @NotNull Array getFactories() { - return factories; - } - - /** - * Create a tree node for an element. - * - * @param the type of an element. - * @param the type of a tree node - * @param element the element - * @return the tree node. - */ - @FxThread - public > @Nullable V createFor(@Nullable final T element) { - - if (element instanceof TreeNode) { - return unsafeCast(element); - } - - final long objectId = ID_GENERATOR.incrementAndGet(); - - V result = null; - - final Array factories = getFactories(); - for (final TreeNodeFactory factory : factories) { - result = factory.createFor(element, objectId); - if (result != null) { - break; - } - } - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java deleted file mode 100644 index c4cd9ee8..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.jme3.animation.*; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.control.anim.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of a tree node factory to make animation nodes. - * - * @author JavaSaBr - */ -public class AnimationTreeNodeFactory implements TreeNodeFactory { - - public static final int PRIORITY = 1; - - @Override - @FxThread - public > @Nullable V createFor(@Nullable final T element, final long objectId) { - - if (element instanceof Animation) { - return unsafeCast(new AnimationTreeNode((Animation) element, objectId)); - } else if (element instanceof BoneTrack) { - return unsafeCast(new AnimationBoneTrackTreeNode((BoneTrack) element, objectId)); - } else if (element instanceof EffectTrack) { - return unsafeCast(new AnimationEffectTrackTreeNode((EffectTrack) element, objectId)); - } else if (element instanceof AudioTrack) { - return unsafeCast(new AnimationAudioTrackTreeNode((AudioTrack) element, objectId)); - } else if (element instanceof SpatialTrack) { - return unsafeCast(new AnimationSpatialTrackTreeNode((SpatialTrack) element, objectId)); - } else if (element instanceof AnimControl) { - return unsafeCast(new AnimationControlTreeNode((AnimControl) element, objectId)); - } - - return null; - } - - @Override - @FxThread - public int getPriority() { - return PRIORITY; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java deleted file mode 100644 index 94e14f32..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.jme3.animation.SkeletonControl; -import com.jme3.bullet.control.*; -import com.jme3.cinematic.events.MotionEvent; -import com.jme3.scene.control.Control; -import com.jme3.scene.control.LightControl; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.LightControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.SkeletonControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.motion.MotionEventTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.BetterCharacterControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.RagdollControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.RigidBodyControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.vehicle.VehicleControlTreeNode; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of a tree node factory to make control nodes. - * - * @author JavaSaBr - */ -public class ControlTreeNodeFactory implements TreeNodeFactory { - - @Override - @FxThread - public > @Nullable V createFor(@Nullable final T element, final long objectId) { - - if (element instanceof MotionEvent) { - return unsafeCast(new MotionEventTreeNode((MotionEvent) element, objectId)); - } else if (element instanceof KinematicRagdollControl) { - return unsafeCast(new RagdollControlTreeNode((KinematicRagdollControl) element, objectId)); - } else if (element instanceof VehicleControl) { - return unsafeCast(new VehicleControlTreeNode((VehicleControl) element, objectId)); - } else if (element instanceof SkeletonControl) { - return unsafeCast(new SkeletonControlTreeNode((SkeletonControl) element, objectId)); - } else if (element instanceof BetterCharacterControl) { - return unsafeCast(new BetterCharacterControlTreeNode((BetterCharacterControl) element, objectId)); - } else if (element instanceof RigidBodyControl) { - return unsafeCast(new RigidBodyControlTreeNode((RigidBodyControl) element, objectId)); - } else if (element instanceof LightControl) { - return unsafeCast(new LightControlTreeNode((LightControl) element, objectId)); - } else if (element instanceof Control) { - return unsafeCast(new ControlTreeNode<>((Control) element, objectId)); - } - - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java deleted file mode 100644 index 410e7780..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/MaterialSettingsTreeNodeFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.node.material.*; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; -import com.ss.editor.ui.control.tree.node.impl.material.settings.*; -import org.jetbrains.annotations.Nullable; - -/** - * The factory to create material settings nodes. - * - * @author JavaSaBr - */ -public class MaterialSettingsTreeNodeFactory implements TreeNodeFactory { - - @Override - @FxThread - public > @Nullable V createFor(@Nullable final T element, final long objectId) { - - if (element instanceof RootMaterialSettings) { - return unsafeCast(new RootMaterialSettingsTreeNode((RootMaterialSettings) element, objectId)); - } else if (element instanceof TexturesSettings) { - return unsafeCast(new TexturesSettingsTreeNode((TexturesSettings) element, objectId)); - } else if (element instanceof ColorsSettings) { - return unsafeCast(new ColorsSettingsTreeNode((ColorsSettings) element, objectId)); - } else if (element instanceof RenderSettings) { - return unsafeCast(new RenderSettingsTreeNode((RenderSettings) element, objectId)); - } else if (element instanceof OtherSettings) { - return unsafeCast(new OtherSettingsTreeNode((OtherSettings) element, objectId)); - } - - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java deleted file mode 100644 index 1ba1e698..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ss.editor.ui.control.tree.node.factory.impl; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.jme3.bullet.objects.VehicleWheel; -import com.jme3.cinematic.MotionPath; -import com.jme3.math.Vector3f; -import com.jme3.scene.VertexBuffer; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.control.tree.node.impl.BufferTreeNode; -import com.ss.editor.ui.control.tree.node.impl.PositionTreeNode; -import com.ss.editor.ui.control.tree.node.impl.VertexBufferTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.motion.MotionPathTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.vehicle.VehicleWheelTreeNode; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactory; -import org.jetbrains.annotations.Nullable; - -import java.nio.Buffer; - -/** - * The implementation of a tree node factory to make primitive nodes. - * - * @author JavaSaBr - */ -public class PrimitiveTreeNodeFactory implements TreeNodeFactory { - - public static final int PRIORITY = 1; - - @Override - @FxThread - public > @Nullable V createFor(@Nullable final T element, final long objectId) { - - if (element instanceof Vector3f) { - return unsafeCast(new PositionTreeNode((Vector3f) element, objectId)); - } else if (element instanceof VertexBuffer) { - return unsafeCast(new VertexBufferTreeNode((VertexBuffer) element, objectId)); - } else if (element instanceof Buffer) { - return unsafeCast(new BufferTreeNode((Buffer) element, objectId)); - } else if (element instanceof VehicleWheel) { - return unsafeCast(new VehicleWheelTreeNode((VehicleWheel) element, objectId)); - } else if (element instanceof MotionPath) { - return unsafeCast(new MotionPathTreeNode((MotionPath) element, objectId)); - } - - return null; - } - - @Override - @FxThread - public int getPriority() { - return PRIORITY; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/BufferTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/BufferTreeNode.java deleted file mode 100644 index 2e5505d0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/BufferTreeNode.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.Buffer; - -/** - * The implementation of the {@link TreeNode} to represent the {@link Buffer} in the editor. - * - * @author JavaSaBr - */ -public class BufferTreeNode extends TreeNode { - - public BufferTreeNode(@NotNull final Buffer element, final long objectId) { - super(element, objectId); - } - - @Override - public @Nullable Image getIcon() { - return Icons.DATA_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return getElement().getClass().getSimpleName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/PositionTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/PositionTreeNode.java deleted file mode 100644 index 260ce124..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/PositionTreeNode.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl; - -import com.jme3.math.Vector3f; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show vectors in the tree. - * - * @author JavaSaBr - */ -public class PositionTreeNode extends TreeNode { - - /** - * The name. - */ - @Nullable - private String name; - - public PositionTreeNode(@NotNull final Vector3f element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.WAY_POINT_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return name == null ? "Point 3D" : name; - } - - @Override - @FxThread - public boolean isNeedToSaveName() { - return true; - } - - @Override - @FxThread - public void setName(@Nullable final String name) { - this.name = name; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/VertexBufferTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/VertexBufferTreeNode.java deleted file mode 100644 index cc2c162a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/VertexBufferTreeNode.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl; - -import com.jme3.scene.VertexBuffer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.Buffer; - -/** - * The implementation of the {@link TreeNode} to represent the {@link VertexBuffer} in the editor. - * - * @author JavaSaBr - */ -public class VertexBufferTreeNode extends TreeNode { - - public VertexBufferTreeNode(@NotNull final VertexBuffer element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.VERTEX_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_VERTEX_BUFFER + " [" + getElement().getBufferType() + "]"; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof ModelNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final VertexBuffer vertexBuffer = getElement(); - - final Buffer data = vertexBuffer.getData(); - if (data == null) return EMPTY_ARRAY; - - final Array> result = ArrayFactory.newArray(TreeNode.class); - result.add(FACTORY_REGISTRY.createFor(data)); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/ControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/ControlTreeNode.java deleted file mode 100644 index 6ee90f77..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/ControlTreeNode.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control; - -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.Named; -import com.ss.editor.extension.scene.control.EditableControl; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.RemoveControlAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} to show a {@link Control} in the tree. - * - * @param the type parameter - * @author JavaSaBr - */ -public class ControlTreeNode extends TreeNode { - - public ControlTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - items.add(new RemoveControlAction(nodeTree, this)); - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.GEAR_16; - } - - @Override - @FxThread - public boolean canCopy() { - return true; - } - - @Override - @FxThread - public boolean canMove() { - return true; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - - final T element = getElement(); - - if (element instanceof EditableControl) { - return ((EditableControl) element).getName(); - } else if (element instanceof Named) { - return ((Named) element).getName(); - } - - return element.getClass().getSimpleName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/LightControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/LightControlTreeNode.java deleted file mode 100644 index 26dbac1d..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/LightControlTreeNode.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control; - -import com.jme3.scene.control.LightControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link TreeNode} to show a {@link LightControl} in the tree. - * - * @author JavaSaBr - */ -public class LightControlTreeNode extends ControlTreeNode { - - public LightControlTreeNode(@NotNull final LightControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_LIGHT_CONTROL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/SkeletonControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/SkeletonControlTreeNode.java deleted file mode 100644 index f027c8b6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/SkeletonControlTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control; - -import com.jme3.animation.SkeletonControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link SkeletonControl}. - * - * @author JavaSaBr - */ -public class SkeletonControlTreeNode extends ControlTreeNode { - - public SkeletonControlTreeNode(@NotNull final SkeletonControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SKELETON_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_SKELETON_CONTROL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationAudioTrackTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationAudioTrackTreeNode.java deleted file mode 100644 index 07be4590..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationAudioTrackTreeNode.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import com.jme3.animation.AudioTrack; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link AudioTrack}. - * - * @author JavaSaBr - */ -public class AnimationAudioTrackTreeNode extends AnimationTrackTreeNode { - - /** - * Instantiates a new Animation audio track model node. - * - * @param element the element - * @param objectId the object id - */ - public AnimationAudioTrackTreeNode(@NotNull final AudioTrack element, final long objectId) { - super(element, objectId); - } - - @NotNull - @Override - protected String computeName() { - final AudioTrack audioTrack = getElement(); - return "Audio track : " + audioTrack.getAudio().getName(); - } - - @Nullable - @Override - public Image getIcon() { - return Icons.AUDIO_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationControlTreeNode.java deleted file mode 100644 index eeb7d5c4..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationControlTreeNode.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.LoopMode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.action.impl.animation.PlaySettingsAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; - -import java.util.Collection; - -/** - * The implementation of node to show {@link AnimControl}. - * - * @author JavaSaBr - */ -public class AnimationControlTreeNode extends ControlTreeNode { - - /** - * The loop mode. - */ - @NotNull - private LoopMode loopMode; - - /** - * The animation speed. - */ - private float speed; - - public AnimationControlTreeNode(@NotNull final AnimControl element, final long objectId) { - super(element, objectId); - this.loopMode = LoopMode.Loop; - this.speed = 1.0F; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - items.add(new PlaySettingsAction(nodeTree, this)); - super.fillContextMenu(nodeTree, items); - } - - /** - * Update settings. - * - * @param loopMode the loop mode. - * @param speed the animation speed. - */ - @FxThread - public void updateSettings(@NotNull LoopMode loopMode, final float speed) { - this.loopMode = loopMode; - this.speed = speed; - } - - /** - * Gets speed. - * - * @return the animation speed. - */ - @FxThread - public float getSpeed() { - return speed; - } - - /** - * Gets loop mode. - * - * @return the loop mode. - */ - @FxThread - public @NotNull LoopMode getLoopMode() { - return loopMode; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_ANIM_CONTROL; - } - - @Override - public @Nullable Image getIcon() { - return Icons.ANIMATION_16; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof ModelNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final Array> result = ArrayFactory.newArray(TreeNode.class); - - final AnimControl element = getElement(); - final Collection animationNames = element.getAnimationNames(); - animationNames.forEach(name -> result.add(FACTORY_REGISTRY.createFor(element.getAnim(name)))); - - result.addAll(super.getChildren(nodeTree)); - - return result; - } - - @Override - @FxThread - public void notifyChildPreAdd(@NotNull final TreeNode treeNode) { - - final AnimationTreeNode animationModelNode = (AnimationTreeNode) treeNode; - animationModelNode.setControl(getElement()); - animationModelNode.setControlModelNode(this); - - super.notifyChildPreAdd(treeNode); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationEffectTrackTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationEffectTrackTreeNode.java deleted file mode 100644 index 69f3a2f1..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationEffectTrackTreeNode.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import com.jme3.animation.EffectTrack; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link EffectTrack}. - * - * @author JavaSaBr - */ -public class AnimationEffectTrackTreeNode extends AnimationTrackTreeNode { - - /** - * Instantiates a new Animation effect track model node. - * - * @param element the element - * @param objectId the object id - */ - public AnimationEffectTrackTreeNode(@NotNull final EffectTrack element, final long objectId) { - super(element, objectId); - } - - @NotNull - @Override - protected String computeName() { - final EffectTrack effectTrack = getElement(); - return "Effect track : " + effectTrack.getEmitter().getName(); - } - - @Nullable - @Override - public Image getIcon() { - return Icons.PARTICLES_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationSpatialTrackTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationSpatialTrackTreeNode.java deleted file mode 100644 index 54b5f045..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationSpatialTrackTreeNode.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import com.jme3.animation.SpatialTrack; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link SpatialTrack}. - * - * @author JavaSaBr - */ -public class AnimationSpatialTrackTreeNode extends AnimationTrackTreeNode { - - public AnimationSpatialTrackTreeNode(@NotNull final SpatialTrack element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - protected @NotNull String computeName() { - return "Spatial track"; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.NODE_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTrackTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTrackTreeNode.java deleted file mode 100644 index 416dbb60..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTrackTreeNode.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import com.jme3.animation.AnimControl; -import com.jme3.animation.Track; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link Track}. - * - * @param the type parameter - * @author JavaSaBr - */ -public abstract class AnimationTrackTreeNode extends TreeNode { - - /** - * The animation control. - */ - @Nullable - private AnimControl control; - - /** - * The cached name. - */ - @Nullable - private String cachedName; - - public AnimationTrackTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - /** - * Sets control. - * - * @param control the animation control. - */ - @FxThread - public void setControl(@Nullable final AnimControl control) { - this.control = control; - this.cachedName = computeName(); - } - - /** - * Compute name string. - * - * @return the string - */ - @FxThread - protected abstract @NotNull String computeName(); - - @Override - @FromAnyThread - public @NotNull String getName() { - return cachedName; - } - - /** - * Gets control. - * - * @return the animation control. - */ - @FxThread - protected @Nullable AnimControl getControl() { - return control; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java deleted file mode 100644 index 556b4da3..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java +++ /dev/null @@ -1,236 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.anim; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.jme3.animation.Track; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; -import com.ss.editor.ui.control.tree.action.impl.animation.*; -import com.ss.editor.model.undo.impl.animation.RenameAnimationNodeOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.AnimationUtils; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link Animation}. - * - * @author JavaSaBr - */ -public class AnimationTreeNode extends TreeNode { - - /** - * The node of an animation control. - */ - @Nullable - private AnimationControlTreeNode controlModelNode; - - /** - * The animation control. - */ - @Nullable - private AnimControl control; - - /** - * The speed. - */ - private float speed; - - /** - * The index of playing animation. - */ - private int channel; - - public AnimationTreeNode(@NotNull final Animation element, final long objectId) { - super(element, objectId); - this.channel = -1; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - final Animation animation = getElement(); - final AnimationControlTreeNode controlModelNode = notNull(getControlModelNode()); - final AnimControl control = controlModelNode.getElement(); - - final int frameCount = AnimationUtils.getFrameCount(animation); - - if (getChannel() < 0 && control.getNumChannels() < 1) { - items.add(new PlayAnimationAction(nodeTree, this)); - items.add(new RemoveAnimationAction(nodeTree, this)); - items.add(new RenameNodeAction(nodeTree, this)); - } else if (getChannel() >= 0 && control.getChannel(getChannel()).getSpeed() < 0.0001F) { - items.add(new PlayAnimationAction(nodeTree, this)); - items.add(new StopAnimationAction(nodeTree, this)); - } else if (getChannel() >= 0) { - items.add(new PauseAnimationAction(nodeTree, this)); - items.add(new StopAnimationAction(nodeTree, this)); - } - - if (getChannel() < 0 && frameCount > 0) { - items.add(new ManualExtractSubAnimationAction(nodeTree, this)); - } - - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - - final Animation element = getElement(); - final Track[] tracks = element.getTracks(); - - return tracks != null && tracks.length > 0 && nodeTree instanceof ModelNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final Animation element = getElement(); - final Track[] tracks = element.getTracks(); - - final Array> result = ArrayFactory.newArray(TreeNode.class, tracks.length); - ArrayUtils.forEach(tracks, track -> result.add(FACTORY_REGISTRY.createFor(track))); - - return result; - } - - @Override - @FxThread - public boolean canEditName() { - return true; - } - - @Override - @FxThread - public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - if (StringUtils.equals(getName(), newName)) return; - - super.changeName(nodeTree, newName); - - final AnimationControlTreeNode controlModelNode = notNull(getControlModelNode()); - final AnimControl control = controlModelNode.getElement(); - final RenameAnimationNodeOperation operation = new RenameAnimationNodeOperation(getName(), newName, control); - - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(operation); - } - - /** - * Gets control model node. - * - * @return the node of an animation control. - */ - @FxThread - public @Nullable AnimationControlTreeNode getControlModelNode() { - return controlModelNode; - } - - /** - * Sets control model node. - * - * @param controlModelNode the node of an animation control. - */ - @FxThread - public void setControlModelNode(@Nullable final AnimationControlTreeNode controlModelNode) { - this.controlModelNode = controlModelNode; - } - - /** - * Gets control. - * - * @return the animation control. - */ - @FxThread - public @Nullable AnimControl getControl() { - return control; - } - - /** - * Sets control. - * - * @param control the animation control. - */ - @FxThread - public void setControl(@Nullable final AnimControl control) { - this.control = control; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return getElement().getName(); - } - - /** - * Gets channel. - * - * @return the index of playing animation. - */ - @FxThread - public int getChannel() { - return channel; - } - - /** - * Sets channel. - * - * @param channel the index of playing animation. - */ - @FxThread - public void setChannel(final int channel) { - this.channel = channel; - } - - /** - * Gets speed. - * - * @return the speed - */ - @FxThread - public float getSpeed() { - return speed; - } - - /** - * Sets speed. - * - * @param speed the speed - */ - @FxThread - public void setSpeed(final float speed) { - this.speed = speed; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - if (getChannel() < 0) return Icons.PLAY_16; - return getSpeed() < 0.0001F ? Icons.PAUSE_16 : Icons.STOP_16; - } - - @Override - @FxThread - public void notifyChildPreAdd(@NotNull final TreeNode treeNode) { - final AnimationTrackTreeNode animationTrackModelNode = (AnimationTrackTreeNode) treeNode; - animationTrackModelNode.setControl(getControl()); - super.notifyChildPreAdd(treeNode); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionEventTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionEventTreeNode.java deleted file mode 100644 index 57754868..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionEventTreeNode.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.motion; - -import com.jme3.cinematic.MotionPath; -import com.jme3.cinematic.events.MotionEvent; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link ControlTreeNode} to show a {@link MotionEvent} in the tree. - * - * @author JavaSaBr - */ -public class MotionEventTreeNode extends ControlTreeNode { - - public MotionEventTreeNode(@NotNull final MotionEvent element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_MOTION_CONTROL; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MOTION_16; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final MotionPath path = getElement().getPath(); - final Array> result = ArrayFactory.newArray(TreeNode.class); - result.add(FACTORY_REGISTRY.createFor(path)); - - return result; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionPathTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionPathTreeNode.java deleted file mode 100644 index 0b7cbed8..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/motion/MotionPathTreeNode.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.motion; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.cinematic.MotionPath; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.PositionTreeNode; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; - -/** - * The implementation of the {@link TreeNode} to show a {@link MotionPath} in the tree. - * - * @author JavaSaBr - */ -public class MotionPathTreeNode extends TreeNode { - - public MotionPathTreeNode(@NotNull final MotionPath element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_MOTION_PATH; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.PATH_16; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final MotionPath element = getElement(); - final int wayPoints = element.getNbWayPoints(); - - final Array> result = ArrayFactory.newArray(TreeNode.class); - - for (int i = 0; i < wayPoints; i++) { - final PositionTreeNode modelNode = notNull(FACTORY_REGISTRY.createFor(element.getWayPoint(i))); - modelNode.setName(Messages.MODEL_FILE_EDITOR_NODE_WAY_POINT + " #" + (i + 1)); - result.add(modelNode); - } - - return result; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof ModelNodeTree; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java deleted file mode 100644 index 7f71a091..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics; - -import com.jme3.bullet.control.BetterCharacterControl; -import com.jme3.bullet.control.CharacterControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link CharacterControl}. - * - * @author JavaSaBr - */ -public class BetterCharacterControlTreeNode extends PhysicsControlTreeNode { - - public BetterCharacterControlTreeNode(@NotNull final BetterCharacterControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.CHARACTER_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_CHARACTER_CONTROL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RagdollControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RagdollControlTreeNode.java deleted file mode 100644 index 0c6583f1..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RagdollControlTreeNode.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics; - -import com.jme3.bullet.control.KinematicRagdollControl; -import com.jme3.bullet.control.VehicleControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link VehicleControl}. - * - * @author JavaSaBr - */ -public class RagdollControlTreeNode extends ControlTreeNode { - - public RagdollControlTreeNode(@NotNull final KinematicRagdollControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.DOLL_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_RAGDOLL_CONTROL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java deleted file mode 100644 index 4e1775f0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics; - -import com.jme3.bullet.control.RigidBodyControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.physics.ReactivatePhysicsControlAction; -import com.ss.editor.ui.control.tree.NodeTree; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link RigidBodyControl}. - * - * @author JavaSaBr - */ -public class RigidBodyControlTreeNode extends PhysicsControlTreeNode { - - public RigidBodyControlTreeNode(@NotNull final RigidBodyControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - - final RigidBodyControl element = getElement(); - - if (element.getMass() == 0F) { - return Icons.STATIC_RIGID_BODY_16; - } - - return Icons.RIGID_BODY_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - - final RigidBodyControl element = getElement(); - - if (element.getMass() == 0F) { - return Messages.MODEL_FILE_EDITOR_NODE_STATIC_RIGID_BODY_CONTROL; - } - - return Messages.MODEL_FILE_EDITOR_NODE_RIGID_BODY_CONTROL; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - final RigidBodyControl element = getElement(); - - if (!element.isActive()) { - items.add(new ReactivatePhysicsControlAction(nodeTree, this)); - } - - super.fillContextMenu(nodeTree, items); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java deleted file mode 100644 index 77f64266..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics.vehicle; - -import com.jme3.bullet.control.VehicleControl; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.physics.PhysicsControlTreeNode; -import com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle.CreateVehicleWheelAction; -import com.ss.editor.ui.control.tree.NodeTree; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link VehicleControl}. - * - * @author JavaSaBr - */ -public class VehicleControlTreeNode extends PhysicsControlTreeNode { - - public VehicleControlTreeNode(@NotNull final VehicleControl element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.VEHICLE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_VEHICLE_CONTROL; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - items.add(new CreateVehicleWheelAction(nodeTree, this)); - - super.fillContextMenu(nodeTree, items); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java deleted file mode 100644 index 799033fa..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleWheelTreeNode.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.control.physics.vehicle; - -import com.jme3.bullet.objects.VehicleWheel; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle.RemoveVehicleWheelAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link VehicleWheel}. - * - * @author JavaSaBr - */ -public class VehicleWheelTreeNode extends TreeNode { - - public VehicleWheelTreeNode(@NotNull final VehicleWheel element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.WHEEL_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final VehicleWheel element = getElement(); - final Spatial wheelSpatial = element.getWheelSpatial(); - return wheelSpatial != null ? Messages.MODEL_FILE_EDITOR_NODE_WHEEL + " [" + wheelSpatial.getName() + "]" : - Messages.MODEL_FILE_EDITOR_NODE_WHEEL; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - super.fillContextMenu(nodeTree, items); - items.add(new RemoveVehicleWheelAction(nodeTree, this)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/LayersRootTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/LayersRootTreeNode.java deleted file mode 100644 index 1273e2ec..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/LayersRootTreeNode.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.layer; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.layer.LayerNodeTree; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.ui.control.tree.action.impl.scene.CreateSceneLayerAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The implementation of {@link TreeNode} to present {@link LayersRoot}. - * - * @author JavaSaBr - */ -public class LayersRootTreeNode extends TreeNode { - - public LayersRootTreeNode(@NotNull final LayersRoot element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SCENE_16; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - items.add(new CreateSceneLayerAction(nodeTree, this)); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final LayersRoot element = getElement(); - final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); - final SceneNode sceneNode = changeConsumer.getCurrentModel(); - return sceneNode.getName(); - } - - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final LayersRoot element = getElement(); - final SceneChangeConsumer changeConsumer = element.getChangeConsumer(); - final SceneNode sceneNode = changeConsumer.getCurrentModel(); - final List layers = sceneNode.getLayers(); - - final Array> result = ArrayFactory.newArray(TreeNode.class); - layers.forEach(layer -> result.add(FACTORY_REGISTRY.createFor(layer))); - - return result; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof LayerNodeTree; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java deleted file mode 100644 index f4ed0ea2..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.layer; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.scene.Spatial; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; -import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; -import com.ss.editor.model.undo.impl.RenameNodeOperation; -import com.ss.editor.model.undo.impl.scene.ChangeVisibleSceneLayerOperation; -import com.ss.editor.ui.control.tree.action.impl.scene.RemoveSceneLayerAction; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.HideableNode; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link NodeTreeNode} for representing the {@link SceneLayer} in the editor. - * - * @author JavaSaBr - */ -public class SceneLayerTreeNode extends TreeNode implements HideableNode { - - public SceneLayerTreeNode(@NotNull final SceneLayer element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - super.fillContextMenu(nodeTree, items); - - final SceneLayer layer = getElement(); - - if (!layer.isBuiltIn()) { - items.add(new RenameNodeAction(nodeTree, this)); - items.add(new RemoveSceneLayerAction(nodeTree, this)); - } - } - - @Override - @FxThread - public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - - final SceneLayer element = getElement(); - - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new RenameNodeOperation(element.getName(), newName, element)); - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return true; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final SceneLayer element = getElement(); - - final Array> result = ArrayFactory.newArray(TreeNode.class); - final ModelChangeConsumer changeConsumer = (ModelChangeConsumer) notNull(nodeTree.getChangeConsumer()); - - final Spatial currentModel = changeConsumer.getCurrentModel(); - currentModel.depthFirstTraversal(spatial -> { - final SceneLayer layer = SceneLayer.getLayer(spatial); - if(layer == element) { - result.add(FACTORY_REGISTRY.createFor(spatial)); - } - }); - - return result; - } - - @Override - @FxThread - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - final Object element = treeNode.getElement(); - return element instanceof Spatial && SceneLayer.getLayer((Spatial) element) != getElement(); - } - - @Override - @FxThread - public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, - final boolean isCopy) { - - final SceneLayer targetLayer = getElement(); - - if (object instanceof Spatial && !isCopy) { - - final Spatial spatial = (Spatial) object; - final SceneLayer currentLayer = SceneLayer.getLayer(spatial); - - final PropertyOperation operation = - new PropertyOperation<>(spatial, SceneLayer.KEY, targetLayer, currentLayer); - - operation.setApplyHandler((sp, layer) -> SceneLayer.setLayer(layer, sp)); - - changeConsumer.execute(operation); - } - - super.accept(changeConsumer, object, isCopy); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final String name = getElement().getName(); - return name == null ? "name is null" : name; - } - - @Override - @FxThread - public boolean canEditName() { - return !getElement().isBuiltIn(); - } - - @Override - @FxThread - public boolean canMove() { - return false; - } - - @Override - @FxThread - public boolean canCopy() { - return false; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.LAYERS_16; - } - - @Override - public boolean isHided() { - return !getElement().isShowed(); - } - - @Override - @FxThread - public void show(@NotNull final NodeTree nodeTree) { - final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); - changeConsumer.execute(new ChangeVisibleSceneLayerOperation(getElement(), true)); - } - - @Override - @FxThread - public void hide(@NotNull final NodeTree nodeTree) { - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - consumer.execute(new ChangeVisibleSceneLayerOperation(getElement(), false)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/AmbientLightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/AmbientLightTreeNode.java deleted file mode 100644 index 60678152..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/AmbientLightTreeNode.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import com.jme3.light.AmbientLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.scene.image.Image; -import com.ss.rlib.common.util.StringUtils; - -/** - * The implementation of {@link LightTreeNode} to present ambient lights. - * - * @author JavaSaBr - */ -public class AmbientLightTreeNode extends LightTreeNode { - - public AmbientLightTreeNode(@NotNull final AmbientLight element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.AMBIENT_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final AmbientLight element = getElement(); - final String name = element.getName(); - return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_AMBIENT_LIGHT : name; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/DirectionalLightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/DirectionalLightTreeNode.java deleted file mode 100644 index 91991fe0..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/DirectionalLightTreeNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import com.jme3.light.DirectionalLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of {@link LightTreeNode} to present direction lights. - * - * @author JavaSaBr - */ -public class DirectionalLightTreeNode extends LightTreeNode { - - public DirectionalLightTreeNode(@NotNull final DirectionalLight element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SUN_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final DirectionalLight element = getElement(); - final String name = element.getName(); - return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_DIRECTION_LIGHT : name; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightProbeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightProbeTreeNode.java deleted file mode 100644 index eca8a6e2..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightProbeTreeNode.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import com.jme3.light.LightProbe; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The tree node to present {@link LightProbe} - * - * @author JavaSaBr - */ -public class LightProbeTreeNode extends TreeNode { - - public LightProbeTreeNode(@NotNull final LightProbe element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_LIGHT_PROBE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java deleted file mode 100644 index 57b403bb..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.light.Light; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.RemoveLightAction; -import com.ss.editor.model.undo.impl.RenameLightOperation; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.StringUtils; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of {@link TreeNode} to present lights. - * - * @param the type parameter - * @author JavaSaBr - */ -public class LightTreeNode extends TreeNode { - - public LightTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final T element = getElement(); - final String name = element.getName(); - return StringUtils.isEmpty(name) ? element.getClass().getSimpleName() : name; - } - - @Override - @FxThread - public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - final T element = getElement(); - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - final String currentName = element.getName(); - consumer.execute(new RenameLightOperation(currentName == null ? "" : currentName, newName, element)); - } - - @Override - @FxThread - public boolean canEditName() { - return true; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.LIGHT_16; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - items.add(new RemoveLightAction(nodeTree, this)); - super.fillContextMenu(nodeTree, items); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/PointLightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/PointLightTreeNode.java deleted file mode 100644 index dbcd6b42..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/PointLightTreeNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import com.jme3.light.PointLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of {@link LightTreeNode} to present point lights. - * - * @author JavaSaBr - */ -public class PointLightTreeNode extends LightTreeNode { - - public PointLightTreeNode(@NotNull final PointLight element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.POINT_LIGHT_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final PointLight element = getElement(); - final String name = element.getName(); - return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_POINT_LIGHT : name; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/SpotLightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/SpotLightTreeNode.java deleted file mode 100644 index 6dcbdbc6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/SpotLightTreeNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.light; - -import com.jme3.light.SpotLight; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of {@link LightTreeNode} to present spot lights. - * - * @author JavaSaBr - */ -public class SpotLightTreeNode extends LightTreeNode { - - public SpotLightTreeNode(@NotNull final SpotLight element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.LAMP_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final SpotLight element = getElement(); - final String name = element.getName(); - return StringUtils.isEmpty(name) ? Messages.MODEL_FILE_EDITOR_NODE_SPOT_LIGHT : name; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java deleted file mode 100644 index b2ceccdd..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/ColorsSettingsTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.node.material.ColorsSettings; -import org.jetbrains.annotations.NotNull; - -/** - * The base presentation of colors settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @author JavaSaBr - */ -public class ColorsSettingsTreeNode extends MaterialSettingsTreeNode { - - public ColorsSettingsTreeNode(@NotNull final ColorsSettings element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MATERIAL_SETTINGS_COLORS; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java deleted file mode 100644 index 19613552..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/MaterialSettingsTreeNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.node.material.MaterialSettings; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base presentation of material settings in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @param the type of material settings. - * @author JavaSaBr - */ -public class MaterialSettingsTreeNode extends TreeNode { - - public MaterialSettingsTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.INFLUENCER_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java deleted file mode 100644 index a384da91..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/OtherSettingsTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.node.material.OtherSettings; -import org.jetbrains.annotations.NotNull; - -/** - * The base presentation of other settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @author JavaSaBr - */ -public class OtherSettingsTreeNode extends MaterialSettingsTreeNode { - - public OtherSettingsTreeNode(@NotNull final OtherSettings element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MATERIAL_SETTINGS_OTHER; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java deleted file mode 100644 index b3e17bac..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RenderSettingsTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.node.material.RenderSettings; -import org.jetbrains.annotations.NotNull; - -/** - * The base presentation of render settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @author JavaSaBr - */ -public class RenderSettingsTreeNode extends MaterialSettingsTreeNode { - - public RenderSettingsTreeNode(@NotNull final RenderSettings element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MATERIAL_SETTINGS_RENDER; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java deleted file mode 100644 index a571b627..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/RootMaterialSettingsTreeNode.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.node.material.*; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -/** - * The base presentation of root settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @author JavaSaBr - */ -public class RootMaterialSettingsTreeNode extends MaterialSettingsTreeNode { - - public RootMaterialSettingsTreeNode(@NotNull final RootMaterialSettings element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final RootMaterialSettings settings = getElement(); - - final Array> children = ArrayFactory.newArray(TreeNode.class); - children.add(FACTORY_REGISTRY.createFor(new TexturesSettings(settings.getMaterial()))); - children.add(FACTORY_REGISTRY.createFor(new ColorsSettings(settings.getMaterial()))); - children.add(FACTORY_REGISTRY.createFor(new RenderSettings(settings.getMaterial()))); - children.add(FACTORY_REGISTRY.createFor(new OtherSettings(settings.getMaterial()))); - - return children; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MATERIAL_SETTINGS_MAIN; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java deleted file mode 100644 index 69f8e0a4..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/material/settings/TexturesSettingsTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.material.settings; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.model.node.material.TexturesSettings; -import org.jetbrains.annotations.NotNull; - -/** - * The base presentation of textures settings of a material in the {@link com.ss.editor.ui.control.tree.NodeTree}. - * - * @author JavaSaBr - */ -public class TexturesSettingsTreeNode extends MaterialSettingsTreeNode { - - public TexturesSettingsTreeNode(@NotNull final TexturesSettings element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MATERIAL_SETTINGS_TEXTURES; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java deleted file mode 100644 index f564bf07..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/BoxCollisionShapeTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.BoxCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of node to show {@link BoxCollisionShape}. - * - * @author JavaSaBr - */ -public class BoxCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public BoxCollisionShapeTreeNode(@NotNull final BoxCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_BOX_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java deleted file mode 100644 index 81f4a579..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CapsuleCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link CapsuleCollisionShape}. - * - * @author JavaSaBr - */ -public class CapsuleCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public CapsuleCollisionShapeTreeNode(@NotNull final CapsuleCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.CAPSULE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_CAPSULE_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java deleted file mode 100644 index 57e6d609..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CollisionShapeTreeNode.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.CollisionShape; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} to show a {@link CollisionShape} in the tree. - * - * @param the type parameter - * @author JavaSaBr - */ -public class CollisionShapeTreeNode extends TreeNode { - - public CollisionShapeTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.GEOMETRY_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final T element = getElement(); - return element.getClass().getSimpleName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java deleted file mode 100644 index 50e2a825..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/ConeCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.ConeCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link ConeCollisionShape}. - * - * @author JavaSaBr - */ -public class ConeCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public ConeCollisionShapeTreeNode(@NotNull final ConeCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.CONE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_CONE_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java deleted file mode 100644 index 677af715..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/CylinderCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.CylinderCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link CylinderCollisionShape}. - * - * @author JavaSaBr - */ -public class CylinderCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public CylinderCollisionShapeTreeNode(@NotNull final CylinderCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.CYLINDER_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_CYLINDER_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java deleted file mode 100644 index 6436f6ce..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/GImpactCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.GImpactCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link GImpactCollisionShape}. - * - * @author JavaSaBr - */ -public class GImpactCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public GImpactCollisionShapeTreeNode(@NotNull final GImpactCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_GIMPACT_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java deleted file mode 100644 index 2bc5f296..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HeightFieldCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link HeightfieldCollisionShape}. - * - * @author JavaSaBr - */ -public class HeightFieldCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public HeightFieldCollisionShapeTreeNode(@NotNull final HeightfieldCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.TERRAIN_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_HEIGHT_FIELD_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java deleted file mode 100644 index 2b3c8cf8..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/HullCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.HullCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link HullCollisionShape}. - * - * @author JavaSaBr - */ -public class HullCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public HullCollisionShapeTreeNode(@NotNull final HullCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_HULL_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java deleted file mode 100644 index 70f719a1..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/MeshCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.MeshCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link MeshCollisionShape}. - * - * @author JavaSaBr - */ -public class MeshCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public MeshCollisionShapeTreeNode(@NotNull final MeshCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_MESH_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java deleted file mode 100644 index f1c97afb..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/PlaneCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.PlaneCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link PlaneCollisionShape}. - * - * @author JavaSaBr - */ -public class PlaneCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public PlaneCollisionShapeTreeNode(@NotNull final PlaneCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.PLANE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PLANE_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java deleted file mode 100644 index f73b281f..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/physics/shape/SphereCollisionShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.physics.shape; - -import com.jme3.bullet.collision.shapes.SphereCollisionShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of node to show {@link SphereCollisionShape}. - * - * @author JavaSaBr - */ -public class SphereCollisionShapeTreeNode extends CollisionShapeTreeNode { - - public SphereCollisionShapeTreeNode(@NotNull final SphereCollisionShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SPHERE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_SPHERE_COLLISION_SHAPE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStateTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStateTreeNode.java deleted file mode 100644 index cbc384a9..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStateTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.scene; - -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The node to present {@link SceneAppState} in the scene model tree. - * - * @author JavaSaBr - */ -public class SceneAppStateTreeNode extends TreeNode { - - public SceneAppStateTreeNode(@NotNull final SceneAppState element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return getElement().getName(); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SETTINGS_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStatesTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStatesTreeNode.java deleted file mode 100644 index 39272db9..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneAppStatesTreeNode.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.scene; - -import com.jme3.util.SafeArrayList; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.model.scene.SceneAppStatesNode; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.scene.SceneNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The node to present scene app states node. - * - * @author JavaSaBr - */ -public class SceneAppStatesTreeNode extends TreeNode { - - public SceneAppStatesTreeNode(@NotNull final SceneAppStatesNode element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SETTINGS_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.SCENE_FILE_EDITOR_TOOL_APP_STATES; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof SceneNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - if (!(nodeTree instanceof SceneNodeTree)) { - return super.getChildren(nodeTree); - } - - final @NotNull SafeArrayList appStates = getElement().getAppStates(); - - final Array> result = ArrayFactory.newArray(TreeNode.class); - appStates.forEach(appState -> result.add(FACTORY_REGISTRY.createFor(appState))); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFilterTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFilterTreeNode.java deleted file mode 100644 index 952f7136..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFilterTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.scene; - -import com.jme3.post.Filter; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The node to present {@link Filter} in the scene model tree. - * - * @author JavaSaBr - */ -public class SceneFilterTreeNode extends TreeNode { - - public SceneFilterTreeNode(@NotNull final Filter element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return getElement().getName(); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.FILTER_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFiltersTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFiltersTreeNode.java deleted file mode 100644 index fc50d5ca..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneFiltersTreeNode.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.scene; - -import com.jme3.util.SafeArrayList; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.filter.SceneFilter; -import com.ss.editor.model.scene.SceneFiltersNode; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.scene.SceneNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The node to present scene filters node. - * - * @author JavaSaBr - */ -public class SceneFiltersTreeNode extends TreeNode { - - public SceneFiltersTreeNode(@NotNull final SceneFiltersNode element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.FILTER_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.SCENE_FILE_EDITOR_NODE_FILTERS; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof SceneNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - if (!(nodeTree instanceof SceneNodeTree)) { - return super.getChildren(nodeTree); - } - - final SafeArrayList filters = getElement().getFilters(); - - final Array> result = ArrayFactory.newArray(TreeNode.class); - filters.forEach(sceneFilter -> result.add(FACTORY_REGISTRY.createFor(sceneFilter.get()))); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneNodeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneNodeTreeNode.java deleted file mode 100644 index 9e57bd78..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/scene/SceneNodeTreeNode.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.scene; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.model.scene.SceneFiltersNode; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.scene.SceneNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link NodeTreeNode} for representing the {@link SceneNode} in the editor. - * - * @author JavaSaBr - */ -public class SceneNodeTreeNode extends NodeTreeNode { - - public SceneNodeTreeNode(@NotNull final SceneNode element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - - if (!(nodeTree instanceof ModelNodeTree)) { - return; - } - - final Menu createMenu = createCreationMenu(nodeTree); - - items.add(createMenu); - items.add(new RenameNodeAction(nodeTree, this)); - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return super.hasChildren(nodeTree) || nodeTree instanceof SceneNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - if (nodeTree instanceof ModelNodeTree) { - return super.getChildren(nodeTree); - } else if (!(nodeTree instanceof SceneNodeTree)) { - return EMPTY_ARRAY; - } - - final SceneNode sceneNode = getElement(); - - //TODO to add other children - final Array> result = ArrayFactory.newArray(TreeNode.class); - result.add(FACTORY_REGISTRY.createFor(new SceneFiltersNode(sceneNode))); - - return result; - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SCENE_16; - } - - @Override - @FxThread - public boolean canMove() { - return false; - } - - @Override - @FxThread - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - return false; - } - - @Override - @FxThread - public boolean canCopy() { - return false; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java deleted file mode 100644 index a8006f78..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AssetLinkNodeTreeNode.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Node; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link SpatialTreeNode} for representing the {@link Node} in the editor. - * - * @author vp -byte - */ -public class AssetLinkNodeTreeNode extends NodeTreeNode { - - public AssetLinkNodeTreeNode(@NotNull final AssetLinkNode element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.LINKED_NODE_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AudioTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AudioTreeNode.java deleted file mode 100644 index 92531cfa..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/AudioTreeNode.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioNode; -import com.jme3.audio.AudioSource; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.action.impl.audio.PlayAudioNodeAction; -import com.ss.editor.ui.control.tree.action.impl.audio.StopAudioNodeAction; -import com.ss.editor.ui.control.tree.NodeTree; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; - -/** - * The implementation of the {@link NodeTreeNode} for representing the {@link AudioNode} in the editor. - * - * @author JavaSaBr - */ -public class AudioTreeNode extends NodeTreeNode { - - public AudioTreeNode(@NotNull final AudioNode element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - if (!(nodeTree instanceof ModelNodeTree)) return; - - final AudioNode element = getElement(); - final AudioData audioData = element.getAudioData(); - final AudioSource.Status status = element.getStatus(); - - if (audioData != null && status != AudioSource.Status.Playing) { - items.add(new PlayAudioNodeAction(nodeTree, this)); - } else if (audioData != null) { - items.add(new StopAudioNodeAction(nodeTree, this)); - } - - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.AUDIO_16; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/GeometryTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/GeometryTreeNode.java deleted file mode 100644 index 16fec3f5..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/GeometryTreeNode.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import com.jme3.material.Material; -import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.ss.editor.Messages; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.action.impl.TangentGeneratorAction; -import com.ss.editor.ui.control.tree.action.impl.geometry.GenerateLoDAction; -import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.scene.control.Menu; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link SpatialTreeNode} to represent the {@link Geometry} in the editor. - * - * @param the type of geometry. - * @author JavaSaBr - */ -public class GeometryTreeNode extends SpatialTreeNode { - - public GeometryTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - public @Nullable Image getIcon() { - return Icons.GEOMETRY_16; - } - - @Override - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - if (!(nodeTree instanceof ModelNodeTree)) return TreeNode.EMPTY_ARRAY; - - final Array> result = ArrayFactory.newArray(TreeNode.class); - - final Geometry geometry = getElement(); - final Mesh mesh = geometry.getMesh(); - final Material material = geometry.getMaterial(); - - if (mesh != null) result.add(FACTORY_REGISTRY.createFor(mesh)); - - result.add(FACTORY_REGISTRY.createFor(material)); - result.addAll(super.getChildren(nodeTree)); - - return result; - } - - @Override - protected @Nullable Menu createToolMenu(@NotNull final NodeTree nodeTree) { - - final Menu toolActions = new Menu(Messages.MODEL_NODE_TREE_ACTION_TOOLS, new ImageView(Icons.INFLUENCER_16)); - toolActions.getItems().addAll(new TangentGeneratorAction(nodeTree, this), - new GenerateLoDAction(nodeTree, this)); - - return toolActions; - } - - @Override - public void add(@NotNull final TreeNode child) { - super.add(child); - - final Geometry geometry = getElement(); - - if (child instanceof MeshTreeNode) { - final Mesh element = (Mesh) child.getElement(); - geometry.setMesh(element); - } - } - - @Override - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - final Object element = treeNode.getElement(); - return (element instanceof Material && isCopy) || super.canAccept(treeNode, isCopy); - } - - @Override - public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, - final boolean isCopy) { - - final Geometry geometry = getElement(); - - if (object instanceof Material) { - - final Material material = (Material) object; - - if (isCopy) { - - final Material clone = material.clone(); - final PropertyOperation operation = - new PropertyOperation<>(geometry, "Material", clone, geometry.getMaterial()); - operation.setApplyHandler(Geometry::setMaterial); - - changeConsumer.execute(operation); - } - } - - super.accept(changeConsumer, object, isCopy); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MaterialTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MaterialTreeNode.java deleted file mode 100644 index 3338bcab..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MaterialTreeNode.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.material.Material; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.MakeAsEmbeddedMaterialAction; -import com.ss.editor.ui.control.tree.action.impl.SaveAsMaterialAction; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.util.NodeUtils; -import javafx.collections.ObservableList; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} to represent the {@link Material} in the editor. - * - * @author JavaSaBr - */ -public class MaterialTreeNode extends TreeNode { - - public MaterialTreeNode(@NotNull final Material element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MATERIAL_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_MATERIAL; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - super.fillContextMenu(nodeTree, items); - - final Material material = getElement(); - final TreeNode parent = notNull(getParent()); - final Object parentElement = parent.getElement(); - final Object linkNode = parentElement instanceof Spatial ? - NodeUtils.findParent((Spatial) parentElement, AssetLinkNode.class::isInstance) : null; - - if (linkNode == null) { - items.add(new SaveAsMaterialAction(nodeTree, this)); - } - - if (material.getKey() != null) { - items.add(new MakeAsEmbeddedMaterialAction(nodeTree, this)); - } - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return false; - } - - @Override - @FxThread - public boolean canCopy() { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MeshTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MeshTreeNode.java deleted file mode 100644 index 327b5b2a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/MeshTreeNode.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import com.jme3.scene.Mesh; -import com.jme3.scene.VertexBuffer; -import com.jme3.util.IntMap; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; - -/** - * The implementation of the {@link TreeNode} to represent the {@link Mesh} in the editor. - * - * @author JavaSaBr - */ -public class MeshTreeNode extends TreeNode { - - public MeshTreeNode(@NotNull final Mesh element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.MESH_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_MESH; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final Array> result = ArrayFactory.newArray(TreeNode.class); - - final Mesh element = getElement(); - final IntMap buffers = element.getBuffers(); - buffers.forEach(entry -> result.add(FACTORY_REGISTRY.createFor(entry.getValue()))); - - return result; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return true; - } - - @Override - @FxThread - public boolean canCopy() { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java deleted file mode 100644 index 94aafe5d..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java +++ /dev/null @@ -1,314 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import static com.ss.editor.util.EditorUtil.*; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.asset.AssetManager; -import com.jme3.asset.ModelKey; -import com.jme3.effect.ParticleEmitter; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.*; -import com.ss.editor.ui.control.tree.action.impl.audio.CreateAudioNodeAction; -import com.ss.editor.ui.control.tree.action.impl.geometry.CreateBoxAction; -import com.ss.editor.ui.control.tree.action.impl.geometry.CreateQuadAction; -import com.ss.editor.ui.control.tree.action.impl.geometry.CreateSphereAction; -import com.ss.editor.ui.control.tree.action.impl.light.CreateAmbientLightAction; -import com.ss.editor.ui.control.tree.action.impl.light.CreateDirectionLightAction; -import com.ss.editor.ui.control.tree.action.impl.light.CreatePointLightAction; -import com.ss.editor.ui.control.tree.action.impl.light.CreateSpotLightAction; -import com.ss.editor.model.undo.impl.AddChildOperation; -import com.ss.editor.model.undo.impl.MoveChildOperation; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.CreateParticleEmitterAction; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; -import com.ss.editor.ui.control.tree.action.impl.terrain.CreateTerrainAction; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.GeomUtils; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.Dragboard; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -/** - * The implementation of the {@link SpatialTreeNode} for representing the {@link Node} in the editor. - * - * @param the type of Node - * @author JavaSaBr - */ -public class NodeTreeNode extends SpatialTreeNode { - - /** - * The additional particle emitter finders. - */ - @NotNull - private static final Array> PARTICLE_EMITTER_FINDERS = ArrayFactory.newArray(Predicate.class); - - /** - * The additional filters of node children. - */ - @NotNull - private static final Array> NODE_CHILDREN_FILTERS = ArrayFactory.newArray(BiPredicate.class); - - /** - * Register the additional particle emitter finder. - * The finder should return true when a node contains some particle emitter. - * - * @param finder the additional particle emitter finder. - */ - @FxThread - public static void registerParticleEmitterFinder(@NotNull final Predicate finder) { - PARTICLE_EMITTER_FINDERS.add(finder); - } - - /** - * Register the additional node children filter. - * The filter should return true when a child should be excluded. - * - * @param finder the additional node children filter. - */ - @FxThread - public static void registerNodeChildrenFilter(@NotNull final BiPredicate finder) { - NODE_CHILDREN_FILTERS.add(finder); - } - - public NodeTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - protected @Nullable Menu createToolMenu(@NotNull final NodeTree nodeTree) { - final Menu toolMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_TOOLS, new ImageView(Icons.INFLUENCER_16)); - toolMenu.getItems().addAll(new OptimizeGeometryAction(nodeTree, this)); - return toolMenu; - } - - @Override - @FxThread - protected @Nullable Menu createCreationMenu(@NotNull final NodeTree nodeTree) { - - final Menu menu = super.createCreationMenu(nodeTree); - if (menu == null) return null; - - final Menu createPrimitiveMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_CREATE_PRIMITIVE, - new ImageView(Icons.ADD_12)); - createPrimitiveMenu.getItems() - .addAll(new CreateBoxAction(nodeTree, this), - new CreateSphereAction(nodeTree, this), - new CreateQuadAction(nodeTree, this)); - - final Menu addLightMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_LIGHT, new ImageView(Icons.ADD_12)); - addLightMenu.getItems() - .addAll(new CreateSpotLightAction(nodeTree, this), - new CreatePointLightAction(nodeTree, this), - new CreateAmbientLightAction(nodeTree, this), - new CreateDirectionLightAction(nodeTree, this)); - - menu.getItems().addAll(new CreateNodeAction(nodeTree, this), - new LoadModelAction(nodeTree, this), - new LinkModelAction(nodeTree, this), - new CreateSkyAction(nodeTree, this), - new CreateEditableSkyAction(nodeTree, this), - new CreateParticleEmitterAction(nodeTree, this), - new CreateAudioNodeAction(nodeTree, this), - new CreateTerrainAction(nodeTree, this), - createPrimitiveMenu, addLightMenu); - - return menu; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - if (!(nodeTree instanceof ModelNodeTree)) { - return; - } - - final T element = getElement(); - final Spatial emitter = NodeUtils.findSpatial(element, ParticleEmitter.class::isInstance); - - if (emitter != null || PARTICLE_EMITTER_FINDERS.search(element, Predicate::test) != null) { - items.add(new ResetParticleEmittersAction(nodeTree, this)); - } - - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof ModelNodeTree; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final T element = getElement(); - final Array> result = ArrayFactory.newArray(TreeNode.class); - final List children = getSpatialChildren(); - for (final Spatial child : children) { - if (NODE_CHILDREN_FILTERS.search(element, child, BiPredicate::test) == null) { - result.add(FACTORY_REGISTRY.createFor(child)); - } - } - result.addAll(super.getChildren(nodeTree)); - - return result; - } - - /** - * Get the children spatial. - * - * @return the children spatial. - */ - @FxThread - protected @NotNull List getSpatialChildren() { - final Node element = getElement(); - return element.getChildren(); - } - - @Override - @FxThread - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - - if (treeNode == this) { - return false; - } - - final Object element = treeNode.getElement(); - if (element instanceof Spatial) { - return GeomUtils.canAttach(getElement(), (Spatial) element, isCopy); - } - - return super.canAccept(treeNode, isCopy); - } - - @Override - @FxThread - public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, - final boolean isCopy) { - - final T newParent = getElement(); - - if (object instanceof Spatial) { - - final Spatial spatial = (Spatial) object; - - if (isCopy) { - - final Spatial clone = spatial.clone(); - final SceneLayer layer = SceneLayer.getLayer(spatial); - - if (layer != null) { - SceneLayer.setLayer(layer, clone); - } - - changeConsumer.execute(new AddChildOperation(clone, newParent, true)); - - } else { - final Node parent = spatial.getParent(); - final int childIndex = parent.getChildIndex(spatial); - changeConsumer.execute(new MoveChildOperation(spatial, parent, newParent, childIndex)); - } - } - - super.accept(changeConsumer, object, isCopy); - } - - @Override - @FxThread - public void add(@NotNull final TreeNode child) { - super.add(child); - - final Node node = getElement(); - final Object toAdd = child.getElement(); - - if (toAdd instanceof Spatial) { - node.attachChildAt((Spatial) toAdd, 0); - } - } - - @Override - @FxThread - public void remove(@NotNull final TreeNode child) { - super.remove(child); - - final Node node = getElement(); - final Object toRemove = child.getElement(); - - if (toRemove instanceof Spatial) { - node.detachChild((Spatial) toRemove); - } - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.NODE_16; - } - - @Override - @FxThread - public boolean canAcceptExternal(@NotNull final Dragboard dragboard) { - return UiUtils.isHasFile(dragboard, FileExtensions.JME_OBJECT); - } - - @Override - @FxThread - public void acceptExternal(@NotNull final Dragboard dragboard, @NotNull final ChangeConsumer consumer) { - UiUtils.handleDroppedFile(dragboard, FileExtensions.JME_OBJECT, getElement(), consumer, this::dropExternalObject); - } - - /** - * Add the external object to this node. - * - * @param node this node. - * @param cons the change consumer. - * @param path the path to the external object. - */ - @FxThread - protected void dropExternalObject(@NotNull final T node, @NotNull final ChangeConsumer cons, - @NotNull final Path path) { - - final SceneLayer defaultLayer = getDefaultLayer(cons); - final Path assetFile = notNull(getAssetFile(path), "Not found asset file for " + path); - final String assetPath = toAssetPath(assetFile); - final ModelKey modelKey = new ModelKey(assetPath); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Spatial loadedModel = assetManager.loadModel(assetPath); - final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); - assetLinkNode.attachLinkedChild(loadedModel, modelKey); - - if (defaultLayer != null) { - SceneLayer.setLayer(defaultLayer, loadedModel); - } - - cons.execute(new AddChildOperation(assetLinkNode, node)); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java deleted file mode 100644 index 046b0f6e..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java +++ /dev/null @@ -1,364 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial; - -import static com.ss.editor.Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL; -import static com.ss.editor.Messages.MODEL_NODE_TREE_ACTION_CREATE; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_MODEL_NODE; -import static com.ss.editor.util.NodeUtils.findParent; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.jme3.bullet.control.CharacterControl; -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.bullet.control.VehicleControl; -import com.jme3.cinematic.events.MotionEvent; -import com.jme3.light.Light; -import com.jme3.light.LightList; -import com.jme3.scene.AssetLinkNode; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.AbstractControl; -import com.jme3.scene.control.Control; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.extension.scene.InvisibleObject; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.model.ModelNodeTree; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.AddUserDataAction; -import com.ss.editor.ui.control.tree.action.impl.DisableAllControlsAction; -import com.ss.editor.ui.control.tree.action.impl.EnableAllControlsAction; -import com.ss.editor.ui.control.tree.action.impl.RemoveNodeAction; -import com.ss.editor.ui.control.tree.action.impl.control.CreateCustomControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.CreateLightControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.CreateMotionControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.physics.CreateCharacterControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.physics.CreateRigidBodyControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.physics.CreateStaticRigidBodyControlAction; -import com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle.CreateVehicleControlAction; -import com.ss.editor.model.undo.impl.AddControlOperation; -import com.ss.editor.model.undo.impl.MoveControlOperation; -import com.ss.editor.model.undo.impl.RenameNodeOperation; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.tree.node.impl.light.LightTreeNode; -import com.ss.editor.util.ControlUtils; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiFunction; - -/** - * The implementation of the {@link TreeNode} to represent a {@link Spatial} in an editor. - * - * @param the type of {@link Spatial}. - * @author JavaSaBr - */ -public class SpatialTreeNode extends TreeNode { - - /** - * The list of additional creation action factories. - */ - @NotNull - private static final Array, NodeTree, MenuItem>> - CREATION_ACTION_FACTORIES = ArrayFactory.newArray(BiFunction.class); - - /** - * The list of additional creation control action factories. - */ - @NotNull - private static final Array, NodeTree, MenuItem>> - CREATION_CONTROL_ACTION_FACTORIES = ArrayFactory.newArray(BiFunction.class); - - /** - * Register the additional creation action factory. - * - * @param actionFactory the additional creation action factory. - */ - public static void registerCreationAction(@NotNull final BiFunction, NodeTree, MenuItem> actionFactory) { - CREATION_ACTION_FACTORIES.add(actionFactory); - } - - /** - * Register the additional creation control action factory. - * - * @param actionFactory the additional creation control action factory. - */ - public static void registerCreationControlAction(@NotNull final BiFunction, NodeTree, MenuItem> actionFactory) { - CREATION_CONTROL_ACTION_FACTORIES.add(actionFactory); - } - - protected SpatialTreeNode(@NotNull final T element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - if (!(nodeTree instanceof ModelNodeTree)) { - return; - } - - final T element = getElement(); - final AssetLinkNode linkNode = findParent(element, AssetLinkNode.class::isInstance); - - if (linkNode == null) { - - final Menu createMenu = createCreationMenu(nodeTree); - - if (createMenu != null) { - createMenu.getItems().sort(ACTION_COMPARATOR); - items.add(createMenu); - } - - final Menu toolMenu = createToolMenu(nodeTree); - if (toolMenu != null) { - toolMenu.getItems().sort(ACTION_COMPARATOR); - items.add(toolMenu); - } - } - - if (linkNode == null || element == linkNode) { - items.add(new AddUserDataAction(nodeTree, this)); - } - - if (canRemove()) { - items.add(new RemoveNodeAction(nodeTree, this)); - } - - NodeUtils.children(element) - .flatMap(ControlUtils::controls) - .filter(control -> !ControlUtils.isEnabled(control)) - .findAny() - .ifPresent(c -> items.add(new EnableAllControlsAction(nodeTree, this))); - - NodeUtils.children(element) - .flatMap(ControlUtils::controls) - .filter(ControlUtils::isEnabled) - .findAny() - .ifPresent(c -> items.add(new DisableAllControlsAction(nodeTree, this))); - - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - public boolean canMove() { - return true; - } - - @Override - @FxThread - public boolean canCopy() { - return true; - } - - @Override - @FxThread - public boolean canAccept(@NotNull final TreeNode treeNode, final boolean isCopy) { - final Object element = treeNode.getElement(); - return element instanceof AbstractControl || super.canAccept(treeNode, isCopy); - } - - @Override - @FxThread - public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final Object object, - final boolean isCopy) { - - final T spatial = getElement(); - - if (object instanceof AbstractControl) { - - final AbstractControl control = (AbstractControl) object; - final Spatial prevParent = control.getSpatial(); - - if (isCopy) { - final AbstractControl clone = (AbstractControl) control.jmeClone(); - clone.setSpatial(null); - changeConsumer.execute(new AddControlOperation(clone, spatial)); - } else { - changeConsumer.execute(new MoveControlOperation(control, prevParent, spatial)); - } - } - - super.accept(changeConsumer, object, isCopy); - } - - @Override - @FxThread - public boolean canRemove() { - final Node parent = getElement().getParent(); - return parent != null && parent.getUserData(KEY_MODEL_NODE) != Boolean.TRUE; - } - - /** - * Create creation menu menu. - * - * @param nodeTree the node tree - * @return the menu - */ - @FxThread - protected @Nullable Menu createCreationMenu(@NotNull final NodeTree nodeTree) { - - final T element = getElement(); - - final Menu menu = new Menu(MODEL_NODE_TREE_ACTION_CREATE, new ImageView(Icons.ADD_12)); - final Menu createControlsMenu = new Menu(MODEL_NODE_TREE_ACTION_ADD_CONTROL, new ImageView(Icons.ADD_12)); - - final ObservableList items = createControlsMenu.getItems(); - items.add(new CreateCustomControlAction(nodeTree, this)); - - if (element.getControl(RigidBodyControl.class) == null) { - items.add(new CreateStaticRigidBodyControlAction(nodeTree, this)); - items.add(new CreateRigidBodyControlAction(nodeTree, this)); - } - - if (element.getControl(VehicleControl.class) == null) { - items.add(new CreateVehicleControlAction(nodeTree, this)); - } - - if (element.getControl(CharacterControl.class) == null) { - items.add(new CreateCharacterControlAction(nodeTree, this)); - } - - if (element.getControl(MotionEvent.class) == null) { - items.add(new CreateMotionControlAction(nodeTree, this)); - } - - items.add(new CreateLightControlAction(nodeTree, this)); - - for (final BiFunction, NodeTree, MenuItem> factory : CREATION_CONTROL_ACTION_FACTORIES) { - final MenuItem item = factory.apply(this, nodeTree); - if (item != null) { - items.add(item); - } - } - - items.sort(ACTION_COMPARATOR); - - //final SkeletonControl skeletonControl = element.getControl(SkeletonControl.class); - //if (skeletonControl != null) { - //FIXME items.add(new CreateKinematicRagdollControlAction(nodeTree, this)); - //} - - menu.getItems().add(createControlsMenu); - - for (final BiFunction, NodeTree, MenuItem> factory : CREATION_ACTION_FACTORIES) { - final MenuItem item = factory.apply(this, nodeTree); - if (item != null) { - menu.getItems().add(item); - } - } - - return menu; - } - - /** - * Create tool menu menu. - * - * @param nodeTree the node tree - * @return the menu - */ - @FxThread - protected @Nullable Menu createToolMenu(final @NotNull NodeTree nodeTree) { - return null; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final String name = getElement().getName(); - return name == null ? "name is null" : name; - } - - @Override - @FxThread - public boolean canEditName() { - return true; - } - - @Override - @FxThread - public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return nodeTree instanceof ModelNodeTree; - } - - @Override - @FxThread - public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - - if (StringUtils.equals(getName(), newName)){ - return; - } - - super.changeName(nodeTree, newName); - - final Spatial spatial = getElement(); - final ChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); - consumer.execute(new RenameNodeOperation(spatial.getName(), newName, spatial)); - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final Array> result = ArrayFactory.newArray(TreeNode.class); - final Spatial element = getElement(); - - final LightList lightList = element.getLocalLightList(); - lightList.forEach(light -> { - if (!(light instanceof InvisibleObject)) { - result.add(FACTORY_REGISTRY.createFor(light)); - } - }); - - final int numControls = element.getNumControls(); - - for (int i = 0; i < numControls; i++) { - final Control control = element.getControl(i); - result.add(FACTORY_REGISTRY.createFor(control)); - } - - return result; - } - - @Override - @FxThread - public void add(@NotNull final TreeNode child) { - super.add(child); - - final T element = getElement(); - - if (child instanceof LightTreeNode) { - final Light light = (Light) child.getElement(); - element.addLight(light); - } else if (child instanceof ControlTreeNode) { - final Control control = (Control) child.getElement(); - element.addControl(control); - } - } - - @Override - @FxThread - public void remove(@NotNull final TreeNode child) { - super.remove(child); - - final T element = getElement(); - - if (child instanceof LightTreeNode) { - final Light light = (Light) child.getElement(); - element.removeLight(light); - } else if (child instanceof ControlTreeNode) { - final Control control = (Control) child.getElement(); - element.removeControl(control); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java deleted file mode 100644 index 105b0e43..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/ParticleEmitterTreeNode.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter; - -import com.jme3.effect.ParticleEmitter; -import com.jme3.effect.influencers.ParticleInfluencer; -import com.jme3.effect.shapes.EmitterShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.GeometryTreeNode; -import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer.CreateDefaultParticleInfluencerAction; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer.CreateEmptyParticleInfluencerAction; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.influencer.CreateRadialParticleInfluencerAction; -import com.ss.editor.ui.control.tree.action.impl.particle.emitter.shape.*; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.collections.ObservableList; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link NodeTreeNode} to represent the {@link ParticleEmitter} in the editor. - * - * @author JavaSaBr - */ -public class ParticleEmitterTreeNode extends GeometryTreeNode { - - public ParticleEmitterTreeNode(@NotNull final ParticleEmitter element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.PARTICLES_16; - } - - @Override - @FxThread - public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { - - final ParticleEmitter element = getElement(); - final TreeNode influencerTreeNode = FACTORY_REGISTRY.createFor(element.getParticleInfluencer()); - final TreeNode shapeTreeNode = FACTORY_REGISTRY.createFor(element.getShape()); - - final Array> children = ArrayFactory.newArray(TreeNode.class); - if (influencerTreeNode != null) children.add(influencerTreeNode); - if (shapeTreeNode != null) children.add(shapeTreeNode); - children.addAll(super.getChildren(nodeTree)); - - return children; - } - - @Override - @FxThread - public void fillContextMenu(@NotNull final NodeTree nodeTree, - @NotNull final ObservableList items) { - - final Menu changeShapeMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_CHANGE_SHAPE, - new ImageView(Icons.EDIT_16)); - - changeShapeMenu.getItems().addAll(new CreateBoxShapeEmitterAction(nodeTree, this), - new CreateSphereShapeEmitterAction(nodeTree, this), - new CreatePointShapeEmitterAction(nodeTree, this), - new CreateMeshVertexShapeEmitterAction(nodeTree, this), - new CreateMeshFaceShapeEmitterAction(nodeTree, this), - new CreateMeshConvexHullShapeEmitterAction(nodeTree, this)); - - final Menu changeInfluencerMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_PARTICLE_EMITTER_CHANGE_INFLUENCER, - new ImageView(Icons.EDIT_16)); - - changeInfluencerMenu.getItems().addAll(new CreateEmptyParticleInfluencerAction(nodeTree, this), - new CreateDefaultParticleInfluencerAction(nodeTree, this), - new CreateRadialParticleInfluencerAction(nodeTree, this)); - - items.add(new ResetParticleEmittersAction(nodeTree, this)); - items.add(changeShapeMenu); - items.add(changeInfluencerMenu); - - super.fillContextMenu(nodeTree, items); - } - - @Override - @FxThread - protected @Nullable Menu createToolMenu(@NotNull final NodeTree nodeTree) { - return null; - } - - @Override - @FxThread - protected @Nullable Menu createCreationMenu(@NotNull final NodeTree nodeTree) { - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java deleted file mode 100644 index 4d5b4ddf..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/DefaultParticleInfluencerTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer; - -import com.jme3.effect.influencers.DefaultParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link DefaultParticleInfluencer} in the editor. - * - * @author JavaSaBr - */ -public class DefaultParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { - - public DefaultParticleInfluencerTreeNode(@NotNull final DefaultParticleInfluencer element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_DEFAULT; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java deleted file mode 100644 index 08395ee6..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/EmptyParticleInfluencerTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer; - -import com.jme3.effect.influencers.EmptyParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link EmptyParticleInfluencer} in the editor. - * - * @author JavaSaBr - */ -public class EmptyParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { - - public EmptyParticleInfluencerTreeNode(@NotNull final EmptyParticleInfluencer element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_EMPTY; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java deleted file mode 100644 index 3f70456a..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/ParticleInfluencerTreeNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer; - -import com.jme3.effect.influencers.ParticleInfluencer; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} for representing the {@link ParticleInfluencer} in the editor. - * - * @author JavaSaBr - */ -public class ParticleInfluencerTreeNode extends TreeNode { - - public ParticleInfluencerTreeNode(@NotNull final ParticleInfluencer element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.INFLUENCER_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final ParticleInfluencer element = getElement(); - return element.getClass().getSimpleName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java deleted file mode 100644 index 12980f18..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/influencer/RadialParticleInfluencerTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.influencer; - -import com.jme3.effect.influencers.RadialParticleInfluencer; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link ParticleInfluencerTreeNode} for representing the {@link RadialParticleInfluencer} in the editor. - * - * @author JavaSaBr - */ -public class RadialParticleInfluencerTreeNode extends ParticleInfluencerTreeNode { - - public RadialParticleInfluencerTreeNode(@NotNull final RadialParticleInfluencer element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_INFLUENCER_RADIAL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java deleted file mode 100644 index c4173888..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterBoxShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterBoxShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterShapeTreeNode} in the editor. - * - * @author JavaSaBr - */ -public class EmitterBoxShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterBoxShapeTreeNode(@NotNull final EmitterBoxShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.CUBE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_BOX; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java deleted file mode 100644 index 05d96ef2..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshConvexHullShapeTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterMeshConvexHullShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshConvexHullShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterMeshConvexHullShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterMeshConvexHullShapeTreeNode(@NotNull final EmitterMeshConvexHullShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_CONVEX_HULL; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java deleted file mode 100644 index f44f8620..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshFaceShapeTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterMeshFaceShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshFaceShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterMeshFaceShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterMeshFaceShapeTreeNode(@NotNull final EmitterMeshFaceShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_FACE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java deleted file mode 100644 index 896dd2d1..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterMeshVertexShapeTreeNode.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterMeshVertexShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import org.jetbrains.annotations.NotNull; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterMeshVertexShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterMeshVertexShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterMeshVertexShapeTreeNode(@NotNull final EmitterMeshVertexShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_MESH_VERTEX; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java deleted file mode 100644 index 4cf958c3..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterPointShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterPointShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterPointShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterPointShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterPointShapeTreeNode(@NotNull final EmitterPointShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.POINTS_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_POINT; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java deleted file mode 100644 index 6be9200b..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterShapeTreeNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterShape; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} for representing the {@link EmitterShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterShapeTreeNode extends TreeNode { - - public EmitterShapeTreeNode(@NotNull final EmitterShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.GEOMETRY_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - final EmitterShape element = getElement(); - return element.getClass().getSimpleName(); - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java deleted file mode 100644 index a08a2b0e..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/particle/emitter/shape/EmitterSphereShapeTreeNode.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.particle.emitter.shape; - -import com.jme3.effect.shapes.EmitterSphereShape; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.Icons; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link EmitterShapeTreeNode} for representing the {@link EmitterSphereShape} in the editor. - * - * @author JavaSaBr - */ -public class EmitterSphereShapeTreeNode extends EmitterShapeTreeNode { - - public EmitterSphereShapeTreeNode(@NotNull final EmitterSphereShape element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.SPHERE_16; - } - - @Override - @FromAnyThread - public @NotNull String getName() { - return Messages.MODEL_FILE_EDITOR_NODE_PARTICLE_EMITTER_SHAPE_SPHERE; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java deleted file mode 100644 index 5de8a4bb..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainGridTreeNode.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.terrain; - -import com.jme3.terrain.geomipmap.TerrainGrid; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.control.Menu; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} to represent a {@link TerrainGrid} in an editor. - * - * @author JavaSaBr - */ -public class TerrainGridTreeNode extends NodeTreeNode { - - public TerrainGridTreeNode(@NotNull final TerrainGrid element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.TERRAIN_16; - } - - @Override - @FxThread - protected @Nullable Menu createCreationMenu(@NotNull final NodeTree nodeTree) { - return null; - } - - @Override - @FxThread - protected @Nullable Menu createToolMenu(@NotNull final NodeTree nodeTree) { - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java deleted file mode 100644 index 56fef300..00000000 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/terrain/TerrainQuadTreeNode.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ss.editor.ui.control.tree.node.impl.spatial.terrain; - -import com.jme3.terrain.geomipmap.TerrainQuad; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import javafx.scene.control.Menu; -import javafx.scene.image.Image; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of the {@link TreeNode} to represent a {@link TerrainQuad} in an editor. - * - * @author JavaSaBr - */ -public class TerrainQuadTreeNode extends NodeTreeNode { - - public TerrainQuadTreeNode(@NotNull final TerrainQuad element, final long objectId) { - super(element, objectId); - } - - @Override - @FxThread - public @Nullable Image getIcon() { - return Icons.TERRAIN_16; - } - - @Override - @FxThread - protected @Nullable Menu createToolMenu(@NotNull final NodeTree nodeTree) { - return null; - } -} diff --git a/src/main/java/com/ss/editor/ui/css/CssColorTheme.java b/src/main/java/com/ss/editor/ui/css/CssColorTheme.java deleted file mode 100644 index e3eb6304..00000000 --- a/src/main/java/com/ss/editor/ui/css/CssColorTheme.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.ss.editor.ui.css; - -import com.ss.editor.annotation.FromAnyThread; -import javafx.scene.paint.Color; -import org.jetbrains.annotations.NotNull; - -/** - * The list of color themes. - * - * @author JavaSaBr - */ -public enum CssColorTheme { - LIGHT("/ui/css/light-color.css", "White", Color.web("#5d626e")), - SHADOW("/ui/css/shadow-color.css", "Shadow", Color.web("#c8d2e1")), - DARK("/ui/css/dark-color.css", "Dark", Color.web("#c8dae2")),; - - @NotNull - public static final CssColorTheme[] VALUES = values(); - - @NotNull - public static CssColorTheme valueOf(final int index) { - return VALUES[index]; - } - - /** - * The icon color. - */ - @NotNull - private final Color iconColor; - - /** - * The css file. - */ - @NotNull - private final String cssFile; - - /** - * The name of this theme. - */ - @NotNull - private final String name; - - CssColorTheme(@NotNull final String cssFile, @NotNull final String name, @NotNull final Color iconColor) { - this.cssFile = cssFile; - this.name = name; - this.iconColor = iconColor; - } - - /** - * @return the name of this theme. - */ - @FromAnyThread - public @NotNull String getName() { - return name; - } - - /** - * @return the css file. - */ - @FromAnyThread - public @NotNull String getCssFile() { - return cssFile; - } - - /** - * @return the icon color. - */ - @FromAnyThread - public @NotNull Color getIconColor() { - return iconColor; - } - - /** - * @return true if this theme is dark. - */ - @FromAnyThread - public boolean needRepaintIcons() { - return true; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/com/ss/editor/ui/css/CssRegistry.java b/src/main/java/com/ss/editor/ui/css/CssRegistry.java deleted file mode 100644 index d6cffb83..00000000 --- a/src/main/java/com/ss/editor/ui/css/CssRegistry.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ss.editor.ui.css; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import org.jetbrains.annotations.NotNull; - -import java.net.URL; - -/** - * The registry of available css files. - * - * @author JavaSaBr - */ -public class CssRegistry { - - @NotNull - private static final CssRegistry INSTANCE = new CssRegistry(); - - @FromAnyThread - public static @NotNull CssRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of available css files. - */ - @NotNull - private final Array availableCssFiles; - - private CssRegistry() { - this.availableCssFiles = ArrayFactory.newArray(String.class); - } - - /** - * Add the CSS file to this registry. - * - * @param cssFile the URL to the CSS file. - */ - @FromAnyThread - public void register(@NotNull final URL cssFile) { - availableCssFiles.add(cssFile.toExternalForm()); - } - - /** - * Add the CSS file to this registry. - * - * @param cssFile the path to CSS file. - * @param classLoader the class loader which can load this path. - */ - @FromAnyThread - public void register(@NotNull final String cssFile, @NotNull final ClassLoader classLoader) { - register(notNull(classLoader.getResource(cssFile))); - } - - /** - * Get a list of available CSS files. - * - * @return the list of available css files. - */ - @FromAnyThread - public @NotNull Array getAvailableCssFiles() { - return availableCssFiles; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/AbstractSimpleEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/AbstractSimpleEditorDialog.java deleted file mode 100644 index 37359dcf..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/AbstractSimpleEditorDialog.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.ss.editor.ui.dialog; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.control.Button; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The simple implementation of the dialog. - * - * @author JavaSaBr - */ -public abstract class AbstractSimpleEditorDialog extends EditorDialog { - - /** - * The constant DEFAULT_LABEL_W_PERCENT. - */ - public static final double DEFAULT_LABEL_W_PERCENT = 0.4; - - /** - * The constant DEFAULT_FIELD_W_PERCENT. - */ - public static final double DEFAULT_FIELD_W_PERCENT = 0.6; - - /** - * The constant DEFAULT_LABEL_W_PERCENT2. - */ - public static final double DEFAULT_LABEL_W_PERCENT2 = 0.5; - - /** - * The constant DEFAULT_FIELD_W_PERCENT2. - */ - public static final double DEFAULT_FIELD_W_PERCENT2 = 0.5; - - /** - * The constant DEFAULT_LABEL_W_PERCENT3. - */ - public static final double DEFAULT_LABEL_W_PERCENT3 = 0.6; - - /** - * The constant DEFAULT_FIELD_W_PERCENT3. - */ - public static final double DEFAULT_FIELD_W_PERCENT3 = 0.4; - - /** - * The constant DEFAULT_FIELD_W_PERCENT4. - */ - public static final double DEFAULT_FIELD_W_PERCENT4 = 0.3; - - /** - * The executing manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The ok button. - */ - @Nullable - private Button okButton; - - /** - * The close button. - */ - @Nullable - private Button closeButton; - - /** - * True if this dialog is ready. - */ - private boolean ready; - - /** - * Instantiates a new Abstract simple editor dialog. - */ - public AbstractSimpleEditorDialog() { - ready = true; - } - - /** - * Is ready boolean. - * - * @return true if this dialog is ready. - */ - protected boolean isReady() { - return ready; - } - - @Override - @FxThread - protected void processKey(@NotNull final KeyEvent event) { - super.processKey(event); - final Button okButton = getOkButton(); - if (okButton != null && event.getCode() == KeyCode.ENTER && !okButton.isDisable()) { - processOk(); - } - } - - @Override - @FxThread - protected void createContent(@NotNull final GridPane root) { - super.createContent(root); - } - - /** - * Gets the ok button. - * - * @return the ok button. - */ - @FxThread - protected @Nullable Button getOkButton() { - return okButton; - } - - /** - * Gets the close button. - * - * @return the close button. - */ - @FxThread - protected @Nullable Button getCloseButton() { - return closeButton; - } - - @Override - @FxThread - protected void createActions(@NotNull final VBox root) { - super.createActions(root); - - final HBox container = new HBox(); - - createBeforeActions(container); - - if (needOkButton()) { - okButton = new Button(getButtonOkText()); - okButton.setOnAction(event -> safeProcessOk()); - FXUtils.addClassTo(okButton, CssClasses.DIALOG_BUTTON); - } - - if (needCloseButton()) { - closeButton = new Button(getButtonCloseText()); - closeButton.setOnAction(event -> processClose()); - FXUtils.addClassTo(closeButton, CssClasses.DIALOG_BUTTON); - } - - if (needOkButton()) { - FXUtils.addToPane(okButton, container); - } - - if (needCloseButton()) { - FXUtils.addToPane(closeButton, container); - } - - createAdditionalActions(container); - - if (!container.getChildren().isEmpty()) { - FXUtils.addToPane(container, root); - FXUtils.addClassTo(container, CssClasses.DEF_HBOX); - } - } - - @FxThread - protected void createBeforeActions(@NotNull final HBox container) { - - } - - @FxThread - protected void createAdditionalActions(@NotNull final HBox container) { - - } - - /** - * @return true if need to add an ok button here. - */ - @FromAnyThread - protected boolean needOkButton() { - return true; - } - - /** - * @return true if need to add a close button here. - */ - @FromAnyThread - protected boolean needCloseButton() { - return true; - } - - @FxThread - private void safeProcessOk() { - try { - processOk(); - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); - } - } - - /** - * Gets the button's close text. - * - * @return the the button's close text. - */ - @FromAnyThread - protected @NotNull String getButtonCloseText() { - return Messages.SIMPLE_DIALOG_BUTTON_CLOSE; - } - - /** - * Gets button's ok text. - * - * @return the button's ok text. - */ - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_OK; - } - - /** - * Handle ok button. - */ - @FxThread - protected void processOk() { - hide(); - } - - /** - * Handle cancel button. - */ - @FxThread - protected void processClose() { - hide(); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/ConfirmDialog.java b/src/main/java/com/ss/editor/ui/dialog/ConfirmDialog.java deleted file mode 100644 index fef03522..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/ConfirmDialog.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.ss.editor.ui.dialog; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.util.function.Consumer; - -/** - * The implementation of a dialog to ask questions. - * - * @author JavaSaBr - */ -public class ConfirmDialog extends AbstractSimpleEditorDialog { - - @NotNull - private static final Point DIALOG_SIZE = new Point(600, -1); - - /** - * The handler of an answer. - */ - @NotNull - private final Consumer<@Nullable Boolean> handler; - - /** - * The label. - */ - @Nullable - private Label questionLabel; - - public ConfirmDialog(@NotNull final Consumer<@Nullable Boolean> handler, @NotNull final String question) { - this.handler = handler; - final Label questionLabel = getQuestionLabel(); - questionLabel.setText(question); - } - - /** - * @return the label. - */ - @FromAnyThread - private @NotNull Label getQuestionLabel() { - return notNull(questionLabel); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.QUESTION_DIALOG_TITLE; - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - super.createContent(root); - - questionLabel = new Label(); - questionLabel.minWidthProperty().bind(widthProperty().multiply(0.9)); - - FXUtils.addToPane(questionLabel, root); - FXUtils.addClassTo(root, CssClasses.CONFIRM_DIALOG); - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_YES; - } - - @Override - @FromAnyThread - protected @NotNull String getButtonCloseText() { - return Messages.SIMPLE_DIALOG_BUTTON_NO; - } - - @Override - @FxThread - protected void processKey(@NotNull final KeyEvent event) { - if (event.getCode() == KeyCode.ENTER) { - processClose(); - } - } - - @Override - @FxThread - protected void processOk() { - super.processOk(); - handler.accept(Boolean.TRUE); - } - - @Override - @FxThread - protected void processClose() { - super.processClose(); - handler.accept(Boolean.FALSE); - } - - /** - * Process cancel the dialog. - */ - protected void processCancel() { - super.processClose(); - handler.accept(null); - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } - - @Override - @FxThread - protected void createAdditionalActions(@NotNull final HBox container) { - super.createAdditionalActions(container); - - final Button closeButton = new Button(Messages.SIMPLE_DIALOG_BUTTON_CANCEL); - closeButton.setOnAction(event -> processCancel()); - - FXUtils.addClassTo(closeButton, CssClasses.DIALOG_BUTTON); - FXUtils.addToPane(closeButton, container); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/RenameDialog.java b/src/main/java/com/ss/editor/ui/dialog/RenameDialog.java deleted file mode 100644 index 3a34ff3e..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/RenameDialog.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.ss.editor.ui.dialog; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.css.CssClasses; -import com.ss.rlib.fx.util.FXUtils; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The implementation of a dialog for renaming. - * - * @author JavaSaBr - */ -public class RenameDialog extends AbstractSimpleEditorDialog { - - @NotNull - private static final Point DIALOG_SIZE = new Point(400, 0); - - /** - * The function for validation name. - */ - @Nullable - private Function validator; - - /** - * The function for handling a new name. - */ - @Nullable - private Consumer handler; - - /** - * The text field. - */ - @Nullable - private TextField nameField; - - @Override - @FxThread - protected void createContent(@NotNull final GridPane root) { - super.createContent(root); - - final Label nameLabel = new Label(Messages.RENAME_DIALOG_NEW_NAME_LABEL + ":"); - nameLabel.prefWidthProperty().bind(widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); - - nameField = new TextField(); - nameField.textProperty().addListener((observable, oldValue, newValue) -> validateName(newValue)); - nameField.prefWidthProperty().bind(widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - root.add(nameLabel, 0, 0); - root.add(nameField, 1, 0); - - FXUtils.addClassTo(nameLabel, CssClasses.DIALOG_DYNAMIC_LABEL); - FXUtils.addClassTo(nameField, CssClasses.DIALOG_FIELD); - } - - @Override - @FromAnyThread - protected boolean isGridStructure() { - return true; - } - - @Override - @FxThread - public void show(@NotNull final Window owner) { - super.show(owner); - EXECUTOR_MANAGER.addFxTask(() -> getNameField().requestFocus()); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.RENAME_DIALOG_TITLE; - } - - /** - * Sets init name. - * - * @param initName the initial name. - */ - @FxThread - public void setInitName(@NotNull final String initName) { - final TextField nameField = getNameField(); - nameField.setText(initName); - } - - /** - * @return the text field. - */ - @FxThread - private @NotNull TextField getNameField() { - return notNull(nameField); - } - - /** - * @return the function for validation name. - */ - @FxThread - private @Nullable Function getValidator() { - return validator; - } - - /** - * Sets validator. - * - * @param validator the function for validation name. - */ - @FxThread - public void setValidator(@Nullable final Function validator) { - this.validator = validator; - } - - /** - * @return the function for handling a new name. - */ - @FxThread - private @Nullable Consumer getHandler() { - return handler; - } - - /** - * Sets handler. - * - * @param handler the function for handling a new name. - */ - @FxThread - public void setHandler(@Nullable final Consumer handler) { - this.handler = handler; - } - - /** - * Validate a new name. - */ - @FxThread - private void validateName(@NotNull final String name) { - final Function validator = getValidator(); - final Button okButton = getOkButton(); - okButton.setDisable(!(validator == null || validator.apply(name))); - } - - @Override - @FromAnyThread - protected @NotNull String getButtonCloseText() { - return Messages.SIMPLE_DIALOG_BUTTON_CANCEL; - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.RENAME_DIALOG_BUTTON_OK; - } - - /** - * Finish this dialog. - */ - @Override - @FxThread - protected void processOk() { - super.processOk(); - - final Consumer handler = getHandler(); - if (handler == null) return; - - final TextField nameField = getNameField(); - handler.accept(nameField.getText()); - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/about/AboutDialog.java b/src/main/java/com/ss/editor/ui/dialog/about/AboutDialog.java deleted file mode 100644 index f7f23bb5..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/about/AboutDialog.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.ss.editor.ui.dialog.about; - -import com.ss.editor.JfxApplication; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.config.Config; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.component.creator.FileCreator; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.FileUtils; -import javafx.application.HostServices; -import javafx.scene.control.Hyperlink; -import javafx.scene.control.Label; -import javafx.scene.control.TextArea; -import javafx.scene.image.ImageView; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.io.InputStream; - -/** - * The dialog about this editor. - * - * @author JavaSaBr - */ -public class AboutDialog extends AbstractSimpleEditorDialog { - - @NotNull - private static final String PROJECT_HOME = "https://bitbucket.org/JavaSabr/jmonkeybuilder"; - - @NotNull - private static final String FORUM_THREAD = "https://hub.jmonkeyengine.org/t/editor-jmonkeybuilder"; - - @NotNull - private static final Point DIALOG_SIZE = new Point(600, -1); - - @NotNull - private static final String ICONS; - - @NotNull - private static final String LIBRARIES; - - static { - final InputStream iconsResource = FileCreator.class.getResourceAsStream("/credits/icons.txt"); - final InputStream librariesResource = FileCreator.class.getResourceAsStream("/credits/libraries.txt"); - ICONS = FileUtils.read(iconsResource); - LIBRARIES = FileUtils.read(librariesResource); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - super.createContent(root); - - final JfxApplication application = JfxApplication.getInstance(); - final HostServices hostServices = application.getHostServices(); - - final GridPane gridPane = new GridPane(); - - final Label applicationLabel = new Label(Config.TITLE); - applicationLabel.setGraphic(new ImageView(Icons.APPLICATION_64)); - - final Label versionLabel = new Label(Messages.ABOUT_DIALOG_VERSION + ":"); - versionLabel.prefWidthProperty().bind(gridPane.widthProperty().multiply(0.5)); - - final Label versionField = new Label(Config.STRING_VERSION); - - final Label projectHomeLabel = new Label(Messages.ABOUT_DIALOG_PROJECT_HOME + ":"); - - final Hyperlink projectHomeField = new Hyperlink("bitbucket.org"); - projectHomeField.setOnAction(event -> hostServices.showDocument(PROJECT_HOME)); - projectHomeField.setFocusTraversable(false); - - final Label forumThreadLabel = new Label(Messages.ABOUT_DIALOG_FORUM_THREAD + ":"); - - final Hyperlink forumThreadField = new Hyperlink("hub.jmonkeyengine.org"); - forumThreadField.setOnAction(event -> hostServices.showDocument(FORUM_THREAD)); - forumThreadField.setFocusTraversable(false); - - final Label usedLibrariesLabel = new Label(Messages.ABOUT_DIALOG_USED_LIBRARIES + ":"); - usedLibrariesLabel.prefWidthProperty().bind(gridPane.widthProperty()); - - final Label usedIcons = new Label(Messages.ABOUT_DIALOG_USED_ICONS + ":"); - usedIcons.prefWidthProperty().bind(gridPane.widthProperty()); - - final TextArea librariesArea = new TextArea(LIBRARIES); - librariesArea.setEditable(false); - librariesArea.setFocusTraversable(false); - - final TextArea iconsArea = new TextArea(ICONS); - iconsArea.setEditable(false); - iconsArea.setFocusTraversable(false); - - gridPane.add(applicationLabel, 0, 0, 2, 1); - gridPane.add(versionLabel, 0, 1, 1, 1); - gridPane.add(versionField, 1, 1, 1, 1); - gridPane.add(projectHomeLabel, 0, 2, 1, 1); - gridPane.add(projectHomeField, 1, 2, 1, 1); - gridPane.add(forumThreadLabel, 0, 3, 1, 1); - gridPane.add(forumThreadField, 1, 3, 1, 1); - gridPane.add(usedLibrariesLabel, 0, 4, 2, 1); - gridPane.add(librariesArea, 0, 5, 2, 1); - gridPane.add(usedIcons, 0, 6, 2, 1); - gridPane.add(iconsArea, 0, 7, 2, 1); - - FXUtils.addToPane(gridPane, root); - - FXUtils.addClassTo(root, CssClasses.ABOUT_DIALOG); - FXUtils.addClassTo(gridPane, CssClasses.DEF_GRID_PANE); - FXUtils.addClassTo(usedLibrariesLabel, usedIcons, CssClasses.ABOUT_DIALOG_LONG_LABEL); - FXUtils.addClassesTo(versionLabel, projectHomeLabel, forumThreadLabel, usedLibrariesLabel, usedIcons, - versionField, projectHomeField, forumThreadField, CssClasses.SPECIAL_FONT_16); - FXUtils.addClassTo(applicationLabel, CssClasses.ABOUT_DIALOG_TITLE_LABEL); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.ABOUT_DIALOG_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_OK; - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/BaseAssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/BaseAssetEditorDialog.java deleted file mode 100644 index c0f2e40c..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/BaseAssetEditorDialog.java +++ /dev/null @@ -1,371 +0,0 @@ -package com.ss.editor.ui.dialog.asset; - -import static com.ss.editor.Messages.ASSET_EDITOR_DIALOG_TITLE; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.preview.FilePreview; -import com.ss.editor.ui.preview.FilePreviewFactoryRegistry; -import com.ss.editor.util.EditorUtil; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.value.ObservableBooleanValue; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TreeItem; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.nio.file.Path; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The base implementation of the {@link AbstractSimpleEditorDialog} to choose some asset resource. - * - * @author JavaSaBr - */ -public class BaseAssetEditorDialog extends AbstractSimpleEditorDialog { - - /** - * The dialog size. - */ - @NotNull - protected static final Point DIALOG_SIZE = new Point(-1, -1); - - /** - * The registry of available file previews. - */ - @NotNull - protected static final FilePreviewFactoryRegistry FILE_PREVIEW_FACTORY_REGISTRY = FilePreviewFactoryRegistry.getInstance(); - - /** - * The function to handle the choose. - */ - @NotNull - protected final Consumer consumer; - - /** - * The function to validate the choose. - */ - @Nullable - private final Function<@NotNull C, @Nullable String> validator; - - /** - * The list of available previews. - */ - @Nullable - protected Array previews; - - /** - * The label with any warning. - */ - @Nullable - private Label warningLabel; - - public BaseAssetEditorDialog(@NotNull final Consumer consumer) { - this(consumer, null); - } - - public BaseAssetEditorDialog(@NotNull final Consumer consumer, - @Nullable final Function<@NotNull C, @Nullable String> validator) { - this.consumer = consumer; - this.validator = validator; - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - - final HBox container = new HBox(); - - final Region firstPart = buildFirstPart(container); - firstPart.prefHeightProperty().bind(root.heightProperty()); - firstPart.prefWidthProperty().bind(root.widthProperty().multiply(0.5)); - - final Region secondPart = buildSecondPart(container); - secondPart.prefHeightProperty().bind(root.heightProperty()); - secondPart.prefWidthProperty().bind(root.widthProperty().multiply(0.5)); - - FXUtils.addToPane(firstPart, container); - FXUtils.addToPane(secondPart, container); - FXUtils.addToPane(container, root); - - FXUtils.addClassTo(container, CssClasses.DEF_HBOX); - FXUtils.addClassTo(root, CssClasses.ASSET_EDITOR_DIALOG); - } - - /** - * Build the first part of this dialog. - * - * @param container the horizontal container. - * @return the built component. - */ - @FxThread - protected @NotNull Region buildFirstPart(@NotNull final HBox container) { - throw new RuntimeException("unsupported"); - } - - /** - * Get the target object from the asset element. - * - * @param element the asset element. - * @return the target object. - */ - @FxThread - protected @Nullable C getObject(@NotNull final T element) { - throw new RuntimeException("unsupported"); - } - - /** - * Gets consumer. - * - * @return the function for handling the choose. - */ - @FromAnyThread - protected @NotNull Consumer getConsumer() { - return consumer; - } - - /** - * Handle selected element in the tree. - * - * @param newValue the new selected item. - */ - @FxThread - protected void processSelected(@Nullable final TreeItem newValue) { - - final T element = newValue == null ? null : newValue.getValue(); - final String assetPath = element == null ? null : getAssetPath(element); - final Path realFile = element == null ? null : getRealFile(element); - - validate(getWarningLabel(), element); - try { - - if (assetPath != null) { - updatePreview(assetPath); - } else if (realFile != null) { - updatePreview(realFile); - } else { - updatePreview((String) null); - } - - } catch (final Exception e) { - EditorUtil.handleException(LOGGER, this, e); - } - } - - /** - * Try to get an asset path from the element. - * - * @param element the element. - * @return the asset path or null. - */ - @FxThread - protected @Nullable String getAssetPath(@NotNull final T element) { - return null; - } - - /** - * Try to get a real file from the element. - * - * @param element the element. - * @return the real file or null. - */ - @FxThread - protected @Nullable Path getRealFile(@NotNull final T element) { - return null; - } - - /** - * Update the preview of the file. - * - * @param file the file. - */ - @FxThread - private void updatePreview(@NotNull final Path file) { - - final Array previews = getPreviews(); - final FilePreview preview = previews.search(file, FilePreview::isSupport); - previews.forEach(preview, (filePreview, toCheck) -> filePreview != toCheck, - (filePreview, tooCheck) -> filePreview.hide()); - - if (preview == null) { - return; - } - - preview.show(file); - } - - /** - * Update the preview of the object by the asset path. - * - * @param assetPath the asset path of the object. - */ - @FxThread - private void updatePreview(@Nullable final String assetPath) { - - final Array previews = getPreviews(); - - if (assetPath == null) { - previews.forEach(FilePreview::hide); - return; - } - - final FilePreview preview = previews.search(assetPath, FilePreview::isSupport); - previews.forEach(preview, (filePreview, toCheck) -> filePreview != toCheck, - (filePreview, tooCheck) -> filePreview.hide()); - - if (preview == null) { - return; - } - - preview.show(assetPath); - } - - /** - * Validate the resource element. - * - * @param warningLabel the warning label - * @param element the element. - */ - @FxThread - protected void validate(@NotNull final Label warningLabel, @Nullable final T element) { - - final Function<@NotNull C, @Nullable String> validator = getValidator(); - if (validator == null) return; - - final C object = element == null ? null : getObject(element); - final String message = object == null ? null : validator.apply(object); - - if (message == null) { - warningLabel.setText(StringUtils.EMPTY); - warningLabel.setVisible(false); - } else { - warningLabel.setText(message); - warningLabel.setVisible(true); - } - } - - /** - * Build second part parent. - * - * @param container the container - * @return the parent - */ - @FxThread - protected @NotNull Region buildSecondPart(@NotNull final HBox container) { - - final StackPane previewContainer = new StackPane(); - - final Array availablePreviews = FILE_PREVIEW_FACTORY_REGISTRY.createAvailablePreviews(); - availablePreviews.forEach(previewContainer, FilePreview::initialize); - - FXUtils.addClassTo(previewContainer, CssClasses.ASSET_EDITOR_DIALOG_PREVIEW_CONTAINER); - - this.previews = availablePreviews; - - return previewContainer; - } - - /** - * Gets validator. - * - * @return the function for validating the choose. - */ - @FxThread - protected @Nullable Function<@NotNull C, @Nullable String> getValidator() { - return validator; - } - - /** - * @return the label with any warning. - */ - @FxThread - protected @NotNull Label getWarningLabel() { - return notNull(warningLabel); - } - - /** - * Get the list of available file previews. - * - * @return the list of available file previews. - */ - @FxThread - protected @NotNull Array getPreviews() { - return notNull(previews); - } - - @Override - @FxThread - public void hide() { - getPreviews().forEach(FilePreview::release); - super.hide(); - } - - @Override - @FxThread - protected void createBeforeActions(@NotNull final HBox container) { - super.createBeforeActions(container); - - warningLabel = new Label(); - warningLabel.setGraphic(new ImageView(Icons.WARNING_24)); - warningLabel.setVisible(false); - - FXUtils.addClassTo(warningLabel, CssClasses.DIALOG_LABEL_WARNING); - FXUtils.addToPane(warningLabel, container); - } - - @Override - @FxThread - protected void createActions(@NotNull final VBox root) { - super.createActions(root); - - final Button okButton = notNull(getOkButton()); - okButton.disableProperty().bind(buildDisableCondition()); - } - - /** - * Build disable condition. - * - * @return the disable condition. - */ - @FxThread - protected @NotNull BooleanBinding buildDisableCondition() { - final Label warningLabel = getWarningLabel(); - return warningLabel.visibleProperty().or(buildAdditionalDisableCondition()); - } - - /** - * Build additional disable condition. - * - * @return the additional condition. - */ - @FxThread - protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { - throw new RuntimeException("unsupported"); - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return ASSET_EDITOR_DIALOG_TITLE; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/file/AssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/file/AssetEditorDialog.java deleted file mode 100644 index 76bb2c40..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/file/AssetEditorDialog.java +++ /dev/null @@ -1,274 +0,0 @@ -package com.ss.editor.ui.dialog.asset.file; - -import static com.ss.editor.ui.component.asset.tree.resource.ResourceElementFactory.createFor; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.ui.component.asset.tree.ResourceTree; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.dialog.EditorDialog; -import com.ss.editor.ui.dialog.asset.BaseAssetEditorDialog; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.CreatedFileEvent; -import com.ss.editor.ui.event.impl.DeletedFileEvent; -import com.ss.editor.ui.event.impl.RequestSelectFileEvent; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.value.ObservableBooleanValue; -import javafx.event.EventHandler; -import javafx.scene.control.MultipleSelectionModel; -import javafx.scene.control.TreeItem; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * The implementation of the {@link EditorDialog} to choose the object from an asset folder. - * - * @param the type parameter - * @author JavaSaBr - */ -public class AssetEditorDialog extends BaseAssetEditorDialog { - - /** - * The executing manager. - */ - @NotNull - protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); - - /** - * The event manager. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - /** - * The handler created files events. - */ - @NotNull - private final EventHandler createdFileHandler = this::processEvent; - - /** - * The handler selected file events. - */ - @NotNull - private final EventHandler selectFileHandle = this::processEvent; - - /** - * The handler deleted file events, - */ - @NotNull - private final EventHandler deletedFileHandler = this::processEvent; - - /** - * The list of waited files to select. - */ - @NotNull - private final Array waitedFilesToSelect; - - /** - * The tree with all resources. - */ - @Nullable - private ResourceTree resourceTree; - - public AssetEditorDialog(@NotNull final Consumer consumer) { - this(consumer, null); - } - - public AssetEditorDialog(@NotNull final Consumer consumer, @Nullable final Function validator) { - super(consumer, validator); - this.waitedFilesToSelect = ArrayFactory.newArray(Path.class); - } - - /** - * Sets extension filter. - * - * @param extensionFilter the list of available extensions. - */ - @FromAnyThread - public void setExtensionFilter(@NotNull final Array extensionFilter) { - getResourceTree().setExtensionFilter(extensionFilter); - } - - /** - * Sets action tester. - * - * @param actionTester the action tester. - */ - @FromAnyThread - public void setActionTester(@Nullable final Predicate> actionTester) { - getResourceTree().setActionTester(actionTester); - } - - /** - * Sets only folders. - * - * @param onlyFolders true if need to show only folders. - */ - @FromAnyThread - public void setOnlyFolders(final boolean onlyFolders) { - getResourceTree().setOnlyFolders(onlyFolders); - } - - @Override - @FxThread - protected @NotNull Region buildFirstPart(@NotNull final HBox container) { - - resourceTree = new ResourceTree(this::processOpen, false); - resourceTree.getSelectionModel() - .selectedItemProperty() - .addListener((observable, oldValue, newValue) -> processSelected(newValue)); - - return resourceTree; - } - - /** - * The process of opening the element. - * - * @param element the element - */ - @FxThread - protected void processOpen(@NotNull final ResourceElement element) { - hide(); - } - - @Override - @FxThread - public void show(@NotNull final Window owner) { - super.show(owner); - - final EditorConfig editorConfig = EditorConfig.getInstance(); - - final ResourceTree resourceTree = getResourceTree(); - final Path currentAsset = notNull(editorConfig.getCurrentAsset()); - - resourceTree.fill(currentAsset); - - FX_EVENT_MANAGER.addEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler); - FX_EVENT_MANAGER.addEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle); - FX_EVENT_MANAGER.addEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); - - EXECUTOR_MANAGER.addFxTask(resourceTree::requestFocus); - } - - /** - * Handle creating file event. - */ - @FxThread - private void processEvent(@NotNull final CreatedFileEvent event) { - - final Path file = event.getFile(); - - final Array waitedFilesToSelect = getWaitedFilesToSelect(); - final boolean waitedSelect = waitedFilesToSelect.contains(file); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.notifyCreated(file); - - if (waitedSelect) waitedFilesToSelect.fastRemove(file); - if (waitedSelect || event.isNeedSelect()) resourceTree.expandTo(file, true); - } - - /** - * Handle deleting file event. - */ - @FxThread - private void processEvent(@NotNull final DeletedFileEvent event) { - - final Path file = event.getFile(); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.notifyDeleted(file); - } - - /** - * Handle selecting file event. - */ - @FxThread - private void processEvent(@NotNull final RequestSelectFileEvent event) { - - final Path file = event.getFile(); - - final ResourceTree resourceTree = getResourceTree(); - final ResourceElement element = createFor(file); - final TreeItem treeItem = findItemForValue(resourceTree.getRoot(), element); - - if (treeItem == null) { - getWaitedFilesToSelect().add(file); - return; - } - - resourceTree.expandTo(treeItem, true); - } - - /** - * @return the list of waited files to select. - */ - @FromAnyThread - private @NotNull Array getWaitedFilesToSelect() { - return waitedFilesToSelect; - } - - @Override - @FxThread - protected @Nullable Path getRealFile(@NotNull final ResourceElement element) { - return element.getFile(); - } - - @Override - @FxThread - public void hide() { - - FX_EVENT_MANAGER.removeEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler); - FX_EVENT_MANAGER.removeEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle); - FX_EVENT_MANAGER.removeEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); - - super.hide(); - } - - @Override - @FxThread - protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { - final ResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - final ReadOnlyObjectProperty> selectedItemProperty = selectionModel.selectedItemProperty(); - return selectedItemProperty.isNull(); - } - - /** - * @return the tree with all resources. - */ - @FxThread - private @NotNull ResourceTree getResourceTree() { - return notNull(resourceTree); - } - - @Override - @FxThread - protected void processOk() { - super.processOk(); - - final ResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - final TreeItem selectedItem = selectionModel.getSelectedItem(); - - if (selectedItem == null) { - hide(); - return; - } - - processOpen(selectedItem.getValue()); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/file/FileAssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/file/FileAssetEditorDialog.java deleted file mode 100644 index 6270f435..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/file/FileAssetEditorDialog.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ss.editor.ui.dialog.asset.file; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.FolderResourceElement; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import javafx.scene.control.Label; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The implementation of the {@link AssetEditorDialog} for choosing the {@link Path} from asset. - * - * @author JavaSaBr - */ -public class FileAssetEditorDialog extends AssetEditorDialog { - - public FileAssetEditorDialog(@NotNull final Consumer consumer) { - super(consumer); - } - - public FileAssetEditorDialog(@NotNull final Consumer consumer, @Nullable final Function validator) { - super(consumer, validator); - } - - @Override - @FxThread - protected void processOpen(@NotNull final ResourceElement element) { - super.processOpen(element); - final Consumer consumer = getConsumer(); - consumer.accept(element.getFile()); - } - - @Override - @FxThread - protected @Nullable Path getObject(@NotNull final ResourceElement element) { - return element.getFile(); - } - - @Override - @FxThread - protected void validate(@NotNull final Label warningLabel, @Nullable final ResourceElement element) { - super.validate(warningLabel, element); - - final Function<@NotNull Path, @Nullable String> validator = getValidator(); - final boolean visible = warningLabel.isVisible(); - - if (!visible && element instanceof FolderResourceElement) { - warningLabel.setText(Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE); - warningLabel.setVisible(true); - } else if (validator == null) { - warningLabel.setVisible(false); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/file/FolderAssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/file/FolderAssetEditorDialog.java deleted file mode 100644 index 314ba664..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/file/FolderAssetEditorDialog.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ss.editor.ui.dialog.asset.file; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The implementation of the {@link AssetEditorDialog} to choose the {@link Path} from asset. - * - * @author JavaSaBr - */ -public class FolderAssetEditorDialog extends AssetEditorDialog { - - public FolderAssetEditorDialog(@NotNull final Consumer consumer) { - super(consumer); - setOnlyFolders(true); - } - - public FolderAssetEditorDialog(@NotNull final Consumer consumer, - @Nullable final Function validator) { - super(consumer, validator); - setOnlyFolders(true); - } - - @Override - @FxThread - protected void processOpen(@NotNull final ResourceElement element) { - super.processOpen(element); - final Consumer consumer = getConsumer(); - consumer.accept(element.getFile()); - } - - @Override - @FxThread - protected @Nullable Path getObject(@NotNull final ResourceElement element) { - return element.getFile(); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/virtual/StringVirtualAssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/virtual/StringVirtualAssetEditorDialog.java deleted file mode 100644 index 38cbf251..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/virtual/StringVirtualAssetEditorDialog.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ss.editor.ui.dialog.asset.virtual; - -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The implementation to work with string resources. - * - * @author JavaSaBr - */ -public class StringVirtualAssetEditorDialog extends VirtualAssetEditorDialog { - - @NotNull - public static final Function<@NotNull String, @Nullable String> DEFAULT_VALIDATOR = resource -> { - - final String extension = FileUtils.getExtension(resource); - - if (StringUtils.isEmpty(extension)) { - return Messages.ASSET_EDITOR_DIALOG_WARNING_SELECT_FILE; - } - - return null; - }; - - public StringVirtualAssetEditorDialog(@NotNull final Consumer consumer, - @NotNull final Array resources) { - this(consumer, DEFAULT_VALIDATOR, resources); - } - - public StringVirtualAssetEditorDialog(@NotNull final Consumer consumer, - @Nullable final Function<@NotNull String, @Nullable String> validator, - @NotNull final Array resources) { - super(consumer, validator, resources); - } - - @Override - @FromAnyThread - protected @NotNull Class getObjectsType() { - return String.class; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/asset/virtual/VirtualAssetEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/asset/virtual/VirtualAssetEditorDialog.java deleted file mode 100644 index ba5c9890..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/asset/virtual/VirtualAssetEditorDialog.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.ss.editor.ui.dialog.asset.virtual; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.component.virtual.tree.VirtualResourceTree; -import com.ss.editor.ui.component.virtual.tree.resource.RootVirtualResourceElement; -import com.ss.editor.ui.component.virtual.tree.resource.VirtualResourceElement; -import com.ss.editor.ui.component.virtual.tree.resource.VirtualResourceElementFactory; -import com.ss.editor.ui.dialog.asset.BaseAssetEditorDialog; -import com.ss.rlib.common.util.array.Array; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.value.ObservableBooleanValue; -import javafx.scene.control.MultipleSelectionModel; -import javafx.scene.control.TreeItem; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * The implementation of the {@link BaseAssetEditorDialog} to choose the object from a virtual asset. - * - * @param the type parameter - * @author JavaSaBr - */ -public class VirtualAssetEditorDialog extends BaseAssetEditorDialog, C> { - - /** - * The all resources. - */ - @NotNull - private final Array resources; - - /** - * The tree with all resources. - */ - @Nullable - private VirtualResourceTree resourceTree; - - public VirtualAssetEditorDialog(@NotNull final Consumer consumer, @NotNull final Array resources) { - this(consumer, null, resources); - } - - public VirtualAssetEditorDialog(@NotNull final Consumer consumer, - @Nullable final Function<@NotNull C, @Nullable String> validator, - @NotNull final Array resources) { - super(consumer, validator); - this.resources = resources; - } - - /** - * @param pathFunction the path function. - * @see VirtualResourceTree#setPathFunction(Function) - */ - @FromAnyThread - public void setPathFunction(@Nullable final Function pathFunction) { - getResourceTree().setPathFunction(pathFunction); - } - - @Override - @FxThread - protected @Nullable String getAssetPath(@NotNull final VirtualResourceElement element) { - return getResourceTree().getPath(element.getObject()); - } - - @Override - @FxThread - protected @NotNull Region buildFirstPart(@NotNull final HBox container) { - - resourceTree = new VirtualResourceTree<>(getObjectsType()); - resourceTree.getSelectionModel().selectedItemProperty() - .addListener((observable, oldValue, newValue) -> processSelected(newValue)); - - return resourceTree; - } - - /** - * Get the type of presented objects. - * - * @return the type of presented objects. - */ - @FromAnyThread - protected @NotNull Class getObjectsType() { - throw new RuntimeException("unsupported"); - } - - @Override - @FxThread - public void show(@NotNull final Window owner) { - super.show(owner); - - final VirtualResourceTree resourceTree = getResourceTree(); - final RootVirtualResourceElement newRoot = - VirtualResourceElementFactory.build(resources, resourceTree); - - resourceTree.fill(newRoot); - resourceTree.expandAll(); - - EXECUTOR_MANAGER.addFxTask(resourceTree::requestFocus); - } - - @Override - @FxThread - protected @Nullable C getObject(@NotNull final VirtualResourceElement element) { - final Object object = element.getObject(); - final Class type = getObjectsType(); - return type.isInstance(object) ? type.cast(object) : null; - } - - /** - * @return the tree with all resources. - */ - @FxThread - private @NotNull VirtualResourceTree getResourceTree() { - return notNull(resourceTree); - } - - @Override - @FxThread - protected @NotNull ObservableBooleanValue buildAdditionalDisableCondition() { - - final VirtualResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel>> selectionModel = resourceTree.getSelectionModel(); - final ReadOnlyObjectProperty>> selectedItemProperty = selectionModel.selectedItemProperty(); - - final Class type = getObjectsType(); - final BooleanBinding typeCondition = new BooleanBinding() { - - @Override - protected boolean computeValue() { - final TreeItem> treeItem = selectedItemProperty.get(); - return treeItem == null || !type.isInstance(treeItem.getValue().getObject()); - } - - @Override - public Boolean getValue() { - return computeValue(); - } - }; - - return Bindings.or(selectedItemProperty.isNull(), typeCondition); - } - - @Override - @FxThread - protected void processOk() { - super.processOk(); - - final VirtualResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel>> selectionModel = resourceTree.getSelectionModel(); - final TreeItem> selectedItem = selectionModel.getSelectedItem(); - - if (selectedItem == null) { - hide(); - return; - } - - final VirtualResourceElement element = selectedItem.getValue(); - final Object object = element.getObject(); - final Class type = getObjectsType(); - - if (type.isInstance(object)) { - getConsumer().accept(type.cast(object)); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/geometry/GeometrySelectorDialog.java b/src/main/java/com/ss/editor/ui/dialog/geometry/GeometrySelectorDialog.java deleted file mode 100644 index dccc54b6..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/geometry/GeometrySelectorDialog.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.ss.editor.ui.dialog.geometry; - -import com.jme3.scene.Geometry; -import com.jme3.scene.Spatial; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.dialog.node.selector.NodeSelectorDialog; - -import org.jetbrains.annotations.NotNull; - -import java.util.function.Consumer; - -/** - * The implementation of node selector dialog to select a geometry. - * - * @author JavaSaBr - */ -public class GeometrySelectorDialog extends NodeSelectorDialog { - - public GeometrySelectorDialog(@NotNull final Spatial model, @NotNull final Consumer handler) { - super(model, Geometry.class, handler); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.GEOMETRY_SELECTOR_DIALOG_TITLE; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/imports/model/ModelImportDialog.java b/src/main/java/com/ss/editor/ui/dialog/imports/model/ModelImportDialog.java deleted file mode 100644 index b376034a..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/imports/model/ModelImportDialog.java +++ /dev/null @@ -1,419 +0,0 @@ -package com.ss.editor.ui.dialog.imports.model; - -import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_TANGENT_GENERATION; -import static com.ss.editor.config.DefaultSettingsProvider.Preferences.PREF_TANGENT_GENERATION; -import static com.ss.editor.extension.property.EditablePropertyType.*; -import static com.ss.editor.util.EditorUtil.getAssetFile; -import static com.ss.editor.util.EditorUtil.toAssetPath; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.nio.file.StandardOpenOption.*; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.jme3.asset.MaterialKey; -import com.jme3.asset.TextureKey; -import com.jme3.export.binary.BinaryExporter; -import com.jme3.material.MatParam; -import com.jme3.material.MatParamTexture; -import com.jme3.material.Material; -import com.jme3.scene.Geometry; -import com.jme3.scene.Spatial; -import com.jme3.texture.Texture; -import com.ss.editor.FileExtensions; -import com.ss.editor.Messages; -import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.asset.locator.FileSystemAssetLocator; -import com.ss.editor.asset.locator.FolderAssetLocator; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.manager.JmeFilePreviewManager; -import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.TangentGenerator; -import com.ss.editor.plugin.api.file.creator.GenericFileCreator; -import com.ss.editor.plugin.api.property.PropertyDefinition; -import com.ss.editor.util.MaterialSerializer; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.NodeUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.VarTable; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.beans.property.ObjectProperty; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.function.Function; - -/** - * The implementation of a dialog to import external models. - * - * @author JavaSaBr - */ -public class ModelImportDialog extends GenericFileCreator { - - @NotNull - private static final EditorConfig EDITOR_CONFIG = EditorConfig.getInstance(); - - private static final String PROP_FILE = "file"; - private static final String PROP_NEED_MATERIALS_EXPORT = "needMaterialsExport"; - private static final String PROP_MATERIALS_FOLDER = "materialsFolder"; - private static final String PROP_OVERWRITE_MATERIALS = "overwriteMaterials"; - private static final String PROP_OVERWRITE_TEXTURES = "overwriteTextures"; - private static final String PROP_TEXTURES_FOLDER = "texturesFolder"; - - @NotNull - private static final Array MATERIAL_EXPORT_DEPS = ArrayFactory.asArray(PROP_NEED_MATERIALS_EXPORT); - - /** - * The image view to show preview of model. - */ - @Nullable - private ImageView imageView; - - /** - * The rendered file. - */ - @Nullable - private Path renderedFile; - - public ModelImportDialog() { - setTitleText(Messages.IMPORT_MODEL_DIALOG_TITLE); - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_IMPORT; - } - - @Override - @FromAnyThread - protected @NotNull Array getPropertyDefinitions() { - - final Array result = ArrayFactory.newArray(PropertyDefinition.class); - result.add(new PropertyDefinition(EXTERNAL_FILE, Messages.IMPORT_MODEL_DIALOG_EXTERNAL_FILE, PROP_FILE, null)); - result.add(new PropertyDefinition(FOLDER_FROM_ASSET_FOLDER, Messages.IMPORT_MODEL_DIALOG_TEXTURES_FOLDER, PROP_TEXTURES_FOLDER, null)); - result.add(new PropertyDefinition(BOOLEAN, Messages.IMPORT_MODEL_DIALOG_OVERWRITE_TEXTURES, PROP_OVERWRITE_TEXTURES, true)); - result.add(new PropertyDefinition(BOOLEAN, Messages.MODEL_CONVERTER_DIALOG_EXPORT_MATERIALS, PROP_NEED_MATERIALS_EXPORT, false)); - result.add(new PropertyDefinition(FOLDER_FROM_ASSET_FOLDER, MATERIAL_EXPORT_DEPS, Messages.MODEL_CONVERTER_DIALOG_MATERIAL_FOLDER, PROP_MATERIALS_FOLDER, null)); - result.add(new PropertyDefinition(BOOLEAN, MATERIAL_EXPORT_DEPS, Messages.MODEL_CONVERTER_DIALOG_OVERWRITE_MATERIALS, PROP_OVERWRITE_MATERIALS, false)); - - return result; - } - - @Override - @FxThread - protected void createPreview(@NotNull final BorderPane container) { - super.createPreview(container); - imageView = new ImageView(); - imageView.fitHeightProperty().bind(container.heightProperty().subtract(4)); - imageView.fitWidthProperty().bind(container.widthProperty().subtract(4)); - container.setCenter(imageView); - } - - @Override - @FromAnyThread - protected boolean needPreview() { - return true; - } - - /** - * Get the image view. - * - * @return the image view. - */ - @FxThread - private @NotNull ImageView getImageView() { - return notNull(imageView); - } - - @Override - @FxThread - protected boolean validate(@NotNull final VarTable vars) { - - final ImageView imageView = getImageView(); - - if (!vars.has(PROP_FILE)) { - imageView.setImage(null); - return false; - } - - final Path file = vars.get(PROP_FILE); - - if (!JmeFilePreviewManager.isModelFile(file)) { - imageView.setImage(null); - return false; - } - - final Path renderedFile = getRenderedFile(); - if (renderedFile != null && file.equals(renderedFile)) { - return super.validate(vars); - } - - final int width = (int) imageView.getFitWidth(); - final int height = (int) imageView.getFitHeight(); - - final JmeFilePreviewManager previewManager = JmeFilePreviewManager.getInstance(); - previewManager.showExternal(file, width, height); - - final ImageView sourceView = previewManager.getImageView(); - final ObjectProperty imageProperty = imageView.imageProperty(); - imageProperty.bind(sourceView.imageProperty()); - - setRenderedFile(file); - - return super.validate(vars); - } - - @Override - @FxThread - protected void processOk() { - hide(); - UiUtils.incrementLoading(); - EXECUTOR_MANAGER.addBackgroundTask(() -> { - try { - importModel(); - } finally { - EXECUTOR_MANAGER.addFxTask(UiUtils::decrementLoading); - } - }); - } - - @Override - @FromAnyThread - protected @NotNull String getFileExtension() { - return FileExtensions.JME_OBJECT; - } - - /** - * Import the external model in a background thread. - */ - @BackgroundThread - private void importModel() { - - final Path modelFile = notNull(getFileToCreate()); - - final Path parent = modelFile.getParent(); - final VarTable vars = getVars(); - - final Path importedFile = vars.get(PROP_FILE); - - final AssetManager assetManager = EditorUtil.getAssetManager(); - final Spatial model; - - FolderAssetLocator.setIgnore(true); - try { - model = assetManager.loadModel(importedFile.toString()); - } finally { - FolderAssetLocator.setIgnore(false); - } - - if (EDITOR_CONFIG.getBoolean(PREF_TANGENT_GENERATION, PREF_DEFAULT_TANGENT_GENERATION)) { - TangentGenerator.useMikktspaceGenerator(model); - } - - final Path texturesFolder = vars.get(PROP_TEXTURES_FOLDER, parent); - final boolean overwriteTextures = vars.getBoolean(PROP_OVERWRITE_TEXTURES); - - final boolean needExportMaterials = vars.getBoolean(PROP_NEED_MATERIALS_EXPORT); - final Path materialsFolder = vars.get(PROP_MATERIALS_FOLDER, parent); - final boolean overwriteMaterials = vars.getBoolean(PROP_OVERWRITE_MATERIALS, false); - - final Array textures = ArrayFactory.newArray(Texture.class); - final Array geometries = ArrayFactory.newArray(Geometry.class); - - NodeUtils.visitGeometry(model, geometry -> { - - final Material material = geometry.getMaterial(); - if (needExportMaterials) geometries.add(geometry); - - material.getParams().stream() - .filter(MatParamTexture.class::isInstance) - .map(MatParam::getValue) - .filter(Texture.class::isInstance) - .map(Texture.class::cast) - .filter(texture -> texture.getKey() != null) - .forEach(textures::add); - }); - - copyTextures(texturesFolder, overwriteTextures, textures); - - if (needExportMaterials) { - exportMaterials(materialsFolder, overwriteMaterials, geometries); - } - - final Path assetFile = notNull(getAssetFile(modelFile)); - final String assetPath = toAssetPath(assetFile); - - model.setName(assetPath); - - final BinaryExporter exporter = BinaryExporter.getInstance(); - - try (final OutputStream out = Files.newOutputStream(modelFile, WRITE, TRUNCATE_EXISTING, CREATE)) { - exporter.save(model, out); - } catch (final IOException e) { - throw new RuntimeException(e); - } - - notifyFileCreated(modelFile, true); - } - - /** - * Export all embedded materials from the external model. - * - * @param materialsFolder the materials folder. - * @param overwriteMaterials true if we can overwrite existing materials. - * @param geometries the found geometries in the model. - */ - @BackgroundThread - private void exportMaterials(@NotNull final Path materialsFolder, final boolean overwriteMaterials, - @NotNull final Array geometries) { - - if (geometries.isEmpty()) { - return; - } - - final ObjectDictionary resultNameToKey = DictionaryFactory.newObjectDictionary(); - - for (final Geometry geometry : geometries) { - - final Material material = geometry.getMaterial(); - final String originalName = material.getName(); - final String name = StringUtils.isEmpty(geometry.getName()) ? "geom" : geometry.getName(); - final String resultName = StringUtils.isEmpty(originalName) ? "embedded-mat-" + name : originalName; - - final String newKey = resultNameToKey.get(resultName); - if (newKey != null) { - material.setKey(new MaterialKey(newKey)); - continue; - } - - final Path resultFile = materialsFolder.resolve(resultName + "." + FileExtensions.JME_MATERIAL); - - if (!Files.exists(resultFile) || overwriteMaterials) { - try (PrintWriter pout = new PrintWriter(Files.newOutputStream(resultFile, WRITE, TRUNCATE_EXISTING, CREATE))) { - pout.println(MaterialSerializer.serializeToString(material)); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - - final Path assetFile = notNull(getAssetFile(resultFile)); - final String assetPath = toAssetPath(assetFile); - - material.setKey(new MaterialKey(assetPath)); - resultNameToKey.put(resultName, assetPath); - } - } - - /** - * Copy textures from the external model. - * - * @param texturesFolder the textures folder. - * @param overwriteTextures true if need to overwrite existing textures. - * @param textures the found textures. - */ - @BackgroundThread - private void copyTextures(@NotNull final Path texturesFolder, final boolean overwriteTextures, - @NotNull final Array textures) { - - if (textures.isEmpty()) { - return; - } - - final ObjectDictionary oldKeyToNew = DictionaryFactory.newObjectDictionary(); - final Array> newTextureKeys = ArrayFactory.newArray(AssetKey.class); - - for (final Texture texture : textures) { - - final TextureKey textureKey = (TextureKey) texture.getKey(); - if (newTextureKeys.contains(textureKey)) continue; - - final String newKey = oldKeyToNew.get(textureKey.getName(), makeCopyTextureFunction(texturesFolder, overwriteTextures)); - - final TextureKey newTextureKey = new TextureKey(newKey, textureKey.isFlipY()); - newTextureKey.setGenerateMips(textureKey.isGenerateMips()); - newTextureKey.setTextureTypeHint(textureKey.getTextureTypeHint()); - - texture.setKey(newTextureKey); - newTextureKeys.add(newTextureKey); - } - } - - /** - * Create the copy texture function. - * - * @param texturesFolder the textures folder. - * @param overwriteTextures true if we can overwrite existing textures. - * @return the new asset path. - */ - @FromAnyThread - private @NotNull Function makeCopyTextureFunction(@NotNull final Path texturesFolder, - final boolean overwriteTextures) { - return oldPath -> { - - final Path textureFile = Paths.get(oldPath); - final Path fileName = textureFile.getFileName(); - - final Path newTextureFile = texturesFolder.resolve(fileName); - final Path assetFile = notNull(getAssetFile(newTextureFile)); - final String assetPath = toAssetPath(assetFile); - - if (Files.exists(newTextureFile) && !overwriteTextures) { - return assetPath; - } - - try { - Files.copy(textureFile, newTextureFile, StandardCopyOption.REPLACE_EXISTING); - } catch (final IOException e) { - throw new RuntimeException(e); - } - - return assetPath; - }; - } - - /** - * Set the rendered file. - * - * @param renderedFile the rendered file. - */ - @FxThread - private void setRenderedFile(@Nullable final Path renderedFile) { - this.renderedFile = renderedFile; - } - - /** - * Get the rendered file. - * - * @return the rendered file. - */ - @FxThread - private @Nullable Path getRenderedFile() { - return renderedFile; - } - - @Override - @FxThread - public void hide() { - - final JmeFilePreviewManager previewManager = JmeFilePreviewManager.getInstance(); - previewManager.clear(); - - FileSystemAssetLocator.clear(); - - super.hide(); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/plugin/PluginListCell.java b/src/main/java/com/ss/editor/ui/dialog/plugin/PluginListCell.java deleted file mode 100644 index d212b5c7..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/plugin/PluginListCell.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ss.editor.ui.dialog.plugin; - -import com.ss.editor.plugin.EditorPlugin; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import javafx.scene.control.ListCell; -import javafx.scene.image.ImageView; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The implementation of {@link ListCell} to present a plugin. - * - * @author JavaSaBr - */ -public class PluginListCell extends ListCell { - - /** - * The icon. - */ - @NotNull - private final ImageView icon; - - public PluginListCell() { - this.icon = new ImageView(Icons.PLUGIN_16); - FXUtils.addClassTo(this, CssClasses.PLUGIN_LIST_CELL); - DynamicIconSupport.updateListener(this, icon, selectedProperty()); - } - - @Override - protected void updateItem(@Nullable final EditorPlugin item, final boolean empty) { - super.updateItem(item, empty); - - if(item == null) { - setGraphic(null); - setText(StringUtils.EMPTY); - return; - } - - setText(item.getName()); - setGraphic(icon); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/plugin/PluginsDialog.java b/src/main/java/com/ss/editor/ui/dialog/plugin/PluginsDialog.java deleted file mode 100644 index 74f7cb6b..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/plugin/PluginsDialog.java +++ /dev/null @@ -1,464 +0,0 @@ -package com.ss.editor.ui.dialog.plugin; - -import static com.ss.editor.ui.util.UiUtils.toWeb; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.analytics.google.GAEvent; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.manager.PluginManager; -import com.ss.editor.plugin.EditorPlugin; -import com.ss.editor.ui.FxConstants; -import com.ss.editor.ui.Icons; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.dialog.ConfirmDialog; -import com.ss.editor.ui.util.DynamicIconSupport; -import com.ss.rlib.common.plugin.Version; -import com.ss.rlib.fx.util.FXUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.application.Platform; -import javafx.beans.value.ObservableValue; -import javafx.collections.ObservableList; -import javafx.scene.control.Button; -import javafx.scene.control.ListView; -import javafx.scene.image.ImageView; -import javafx.scene.layout.*; -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; -import javafx.scene.web.WebView; -import javafx.stage.FileChooser; -import javafx.stage.FileChooser.ExtensionFilter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.io.File; -import java.net.URL; -import java.util.Arrays; -import java.util.List; - -/** - * The implementation of a dialog to work with plugins. - * - * @author JavaSaBr - */ -public class PluginsDialog extends AbstractSimpleEditorDialog { - - @NotNull - private static final Point DIALOG_SIZE = new Point(1200, -1); - - @NotNull - private static final PluginManager PLUGIN_MANAGER = PluginManager.getInstance(); - - /** - * The original list of installed plugins. - */ - @NotNull - private final Array originalIds; - - /** - * The list of installed plugins. - */ - @Nullable - private ListView pluginListView; - - /** - * The description area. - */ - @Nullable - private WebView descriptionArea; - - /** - * The remove button. - */ - @Nullable - private Button removeButton; - - /** - * The background color. - */ - @Nullable - private Color backgroundColor; - - /** - * The font color. - */ - @Nullable - private Color fontColor; - - /** - * The link color. - */ - @Nullable - private Color linkColor; - - public PluginsDialog() { - this.originalIds = ArrayFactory.newArray(String.class); - refreshPlugins(); - PLUGIN_MANAGER.handlePlugins(plugin -> originalIds.add(plugin.getId())); - } - - @Override - @FxThread - protected void createContent(@NotNull final GridPane root) { - super.createContent(root); - - pluginListView = new ListView<>(); - pluginListView.setCellFactory(param -> new PluginListCell()); - pluginListView.setFixedCellSize(FxConstants.LIST_CELL_HEIGHT); - pluginListView.prefWidthProperty().bind(root.widthProperty().divide(2)); - pluginListView.prefHeightProperty().bind(root.heightProperty()); - - descriptionArea = new WebView(); - - final BorderPane descriptionContainer = new BorderPane(descriptionArea); - descriptionContainer.setVisible(false); - descriptionContainer.prefWidthProperty().bind(root.widthProperty().divide(2)); - descriptionContainer.backgroundProperty().addListener((observable, oldValue, newValue) -> takeColors(newValue)); - - final HBox buttonContainer = new HBox(); - - final Button addButton = new Button(); - addButton.setGraphic(new ImageView(Icons.ADD_12)); - addButton.setOnAction(event -> processAdd()); - - removeButton = new Button(); - removeButton.setGraphic(new ImageView(Icons.REMOVE_12)); - removeButton.setOnAction(event -> processRemove()); - removeButton.setDisable(true); - - pluginListView.getSelectionModel() - .selectedItemProperty() - .addListener(this::onSelected); - - FXUtils.addToPane(addButton, removeButton, buttonContainer); - DynamicIconSupport.addSupport(addButton, removeButton); - - root.add(pluginListView, 0, 0, 1, 1); - root.add(descriptionContainer, 1, 0, 1, 1); - root.add(buttonContainer, 0, 1, 1, 1); - - FXUtils.addClassTo(buttonContainer, CssClasses.DEF_HBOX); - FXUtils.addClassTo(addButton, CssClasses.BUTTON_WITHOUT_RIGHT_BORDER); - FXUtils.addClassTo(removeButton, CssClasses.BUTTON_WITHOUT_LEFT_BORDER); - FXUtils.addClassTo(root, CssClasses.PLUGINS_DIALOG); - FXUtils.addClassesTo(descriptionContainer, CssClasses.WEBVIEW_TEXT_AREA); - } - - /** - * Take CSS colors from background. - * - * @param newValue the new background. - */ - private void takeColors(@Nullable final Background newValue) { - - if (newValue == null) { - setBackgroundColor(null); - setFontColor(null); - return; - } - - final List fills = newValue.getFills(); - if (fills.size() < 3) { - setBackgroundColor(null); - setFontColor(null); - return; - } - - final Paint background = fills.get(0).getFill(); - final Paint font = fills.get(1).getFill(); - final Paint link = fills.get(2).getFill(); - - if (background instanceof Color) { - setBackgroundColor((Color) background); - } - - if (font instanceof Color) { - setFontColor((Color) font); - } - - if (link instanceof Color) { - setLinkColor((Color) link); - } - } - - /** - * Get the background color. - * - * @return the background color. - */ - private @Nullable Color getBackgroundColor() { - return backgroundColor; - } - - /** - * Set the background color. - * - * @param backgroundColor the background color. - */ - private void setBackgroundColor(@Nullable final Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - /** - * Get the font color. - * - * @return the font color. - */ - private @Nullable Color getFontColor() { - return fontColor; - } - - /** - * Set the font color. - * - * @param fontColor the font color. - */ - private void setFontColor(@Nullable final Color fontColor) { - this.fontColor = fontColor; - } - - /** - * Get the link color. - * - * @return the link color. - */ - private @Nullable Color getLinkColor() { - return linkColor; - } - - /** - * Set the link color. - * - * @param linkColor the link color. - */ - private void setLinkColor(@Nullable final Color linkColor) { - this.linkColor = linkColor; - } - - /** - * Get the remove button. - * - * @return the remove button. - */ - private @NotNull Button getRemoveButton() { - return notNull(removeButton); - } - - /** - * Get the description area. - * - * @return the description area. - */ - private @NotNull WebView getDescriptionArea() { - return notNull(descriptionArea); - } - - /** - * Handle the selected plugin. - * - * @param observable the observable property. - * @param oldValue the old selected plugin. - * @param newValue the new selected plugin. - */ - @FxThread - private void onSelected(@NotNull final ObservableValue observable, - @Nullable final EditorPlugin oldValue, @Nullable final EditorPlugin newValue) { - getRemoveButton().setDisable(newValue == null || newValue.isEmbedded()); - final WebView descriptionArea = getDescriptionArea(); - descriptionArea.getParent().setVisible(newValue != null); - descriptionArea.getEngine().loadContent(generateDescription(newValue)); - } - - /** - * Generate HTML description. - * - * @param plugin the plugin. - * @return the html description. - */ - private @NotNull String generateDescription(@Nullable final EditorPlugin plugin) { - if (plugin == null) return StringUtils.EMPTY; - - final String name = plugin.getName(); - final Version version = plugin.getVersion(); - final String description = plugin.getDescription(); - final URL homePageUrl = plugin.getHomePageUrl(); - final String usedGradleDependencies = plugin.getUsedGradleDependencies(); - final String usedMavenDependencies = plugin.getUsedMavenDependencies(); - - final StringBuilder result = new StringBuilder(""); - - final Color backgroundColor = getBackgroundColor(); - final Color fontColor = getFontColor(); - final Color linkColor = getLinkColor(); - - if (backgroundColor != null && fontColor != null && linkColor != null) { - result.append(""); - result.append(""); - } - - result.append(""); - result.append("

").append(name).append("

"); - result.append("

").append(Messages.PLUGINS_DIALOG_VERSION).append(": ").append(version).append("

"); - result.append("

").append(description).append("

"); - - if (homePageUrl != null) { - result.append("

").append(Messages.PLUGINS_DIALOG_HOME_PAGE).append("

"); - } - - if (StringUtils.isNotEmpty(usedGradleDependencies) || StringUtils.isNotEmpty(usedMavenDependencies)) { - result.append("

").append(Messages.PLUGINS_DIALOG_USED_DEPENDENCIES).append(":").append("

"); - - if (StringUtils.isNotEmpty(usedGradleDependencies)) { - result.append("

").append("Gradle:").append("

"); - result.append(usedGradleDependencies); - } - - if (StringUtils.isNotEmpty(usedMavenDependencies)) { - result.append("

").append("Maven:").append("

"); - result.append(usedMavenDependencies); - } - } - - result.append(""); - - return result.toString(); - } - - @Override - @FromAnyThread - protected boolean isGridStructure() { - return true; - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.PLUGINS_DIALOG_TITLE; - } - - /** - * @return the list of installed plugins. - */ - @FxThread - private @NotNull ListView getPluginListView() { - return notNull(pluginListView); - } - - /** - * Refresh the list of installed plugins. - */ - @FxThread - private void refreshPlugins() { - - final ObservableList items = pluginListView.getItems(); - items.clear(); - - PLUGIN_MANAGER.handlePlugins(items::add); - } - - /** - * Process remove. - */ - @FxThread - private void processRemove() { - - final ListView pluginListView = getPluginListView(); - final EditorPlugin toRemove = pluginListView.getSelectionModel() - .getSelectedItem(); - - if(toRemove.isEmbedded()) { - return; - } - - PLUGIN_MANAGER.removePlugin(toRemove); - - refreshPlugins(); - } - - /** - * @return the list of original plugin ids. - */ - @FxThread - private @NotNull Array getOriginalIds() { - return originalIds; - } - - @Override - @FxThread - protected void processClose() { - super.processClose(); - - final Array newIds = ArrayFactory.newArray(String.class); - - PLUGIN_MANAGER.handlePlugins(plugin -> newIds.add(plugin.getId())); - - final String[] original = newIds.toArray(String.class); - final String[] toCompare = originalIds.toArray(String.class); - - if (Arrays.equals(original, toCompare)) { - return; - } - - final ConfirmDialog dialog = new ConfirmDialog(result -> { - if (Boolean.TRUE.equals(result)) Platform.exit(); - }, Messages.PLUGINS_DIALOG_QUESTION); - dialog.show(getDialog()); - } - - /** - * Process install a plugin. - */ - @FxThread - private void processAdd() { - - GAnalytics.sendPageView("PluginChooseDialog", null, "/dialog/PluginChooseDialog"); - GAnalytics.sendEvent(GAEvent.Category.DIALOG, GAEvent.Action.DIALOG_OPENED, "PluginChooseDialog"); - - final FileChooser chooser = new FileChooser(); - chooser.setTitle(Messages.PLUGINS_DIALOG_FILE_CHOOSER_TITLE); - chooser.setSelectedExtensionFilter(new ExtensionFilter(Messages.PLUGINS_DIALOG_FILE_CHOOSER_FILTER, "*.zip")); - chooser.setInitialDirectory(new File(System.getProperty("user.home"))); - - final File result = chooser.showOpenDialog(getDialog()); - - if (result == null) { - return; - } - - PLUGIN_MANAGER.installPlugin(result.toPath()); - - refreshPlugins(); - } - - @Override - @FromAnyThread - protected boolean needOkButton() { - return false; - } - - @Override - @FromAnyThread - protected @NotNull String getButtonCloseText() { - return Messages.SIMPLE_DIALOG_BUTTON_CLOSE; - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/save/SaveAsEditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/save/SaveAsEditorDialog.java deleted file mode 100644 index 2431bdc4..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/save/SaveAsEditorDialog.java +++ /dev/null @@ -1,426 +0,0 @@ -package com.ss.editor.ui.dialog.save; - -import static com.ss.editor.Messages.SAVE_AS_EDITOR_DIALOG_FIELD_FILENAME; -import static com.ss.editor.Messages.SAVE_AS_EDITOR_DIALOG_TITLE; -import static com.ss.editor.ui.component.asset.tree.resource.ResourceElementFactory.createFor; -import static com.ss.editor.ui.util.UiUtils.findItemForValue; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.ui.component.asset.tree.ResourceTree; -import com.ss.editor.ui.component.asset.tree.resource.ResourceElement; -import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; -import com.ss.editor.ui.dialog.EditorDialog; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.CreatedFileEvent; -import com.ss.editor.ui.event.impl.DeletedFileEvent; -import com.ss.editor.ui.event.impl.RequestSelectFileEvent; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.fx.util.FXUtils; -import javafx.event.EventHandler; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.*; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * The implementation of the {@link EditorDialog} to choose how to save an object. - * - * @author JavaSaBr - */ -public class SaveAsEditorDialog extends AbstractSimpleEditorDialog { - - /** - * The constant DIALOG_SIZE. - */ - @NotNull - protected static final Point DIALOG_SIZE = new Point(900, -1); - - /** - * The event manager. - */ - @NotNull - protected static final FxEventManager FX_EVENT_MANAGER = FxEventManager.getInstance(); - - @NotNull - private final EventHandler createdFileHandler = this::processEvent; - - @NotNull - private final EventHandler selectFileHandle = this::processEvent; - - @NotNull - private final EventHandler deletedFileHandler = this::processEvent; - - /** - * The list of waited files to select. - */ - @NotNull - private final Array waitedFilesToSelect; - - /** - * The function for handling the choose. - */ - @NotNull - protected final Consumer<@NotNull Path> consumer; - - /** - * The file extension. - */ - @Nullable - private String extension; - - /** - * The tree with all resources. - */ - @Nullable - private ResourceTree resourceTree; - - /** - * The filename field. - */ - @Nullable - private TextField fileNameField; - - public SaveAsEditorDialog(@NotNull final Consumer<@NotNull Path> consumer) { - this.waitedFilesToSelect = ArrayFactory.newArray(Path.class); - this.consumer = consumer; - } - - /** - * Get the title of filename field. - * - * @return the title of filename field. - */ - @FxThread - protected @NotNull String getFileNameLabelText() { - return SAVE_AS_EDITOR_DIALOG_FIELD_FILENAME; - } - - /** - * Set the target file extension. - * - * @param extension the target file extension. - */ - @FxThread - public void setExtension(@NotNull final String extension) { - this.extension = extension; - getResourceTree().setExtensionFilter(ArrayFactory.asArray(extension)); - } - - /** - * Get the target file extension. - * - * @return the target file extension. - */ - @FxThread - private @NotNull String getExtension() { - return extension == null ? "" : extension; - } - - /** - * Sets action tester. - * - * @param actionTester the action tester. - */ - @FxThread - public void setActionTester(@NotNull final Predicate<@NotNull Class> actionTester) { - getResourceTree().setActionTester(actionTester); - } - - @Override - @FxThread - protected void createContent(@NotNull final VBox root) { - super.createContent(root); - - final HBox container = new HBox(); - container.prefWidthProperty().bind(widthProperty()); - - final GridPane settingsContainer = new GridPane(); - settingsContainer.prefWidthProperty().bind(container.widthProperty().multiply(0.5)); - settingsContainer.prefHeightProperty().bind(container.heightProperty()); - - resourceTree = new ResourceTree(null, true); - resourceTree.prefWidthProperty().bind(container.widthProperty().multiply(0.5)); - - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - selectionModel.selectedItemProperty().addListener((observable, oldValue, newValue) -> processSelection(newValue)); - - createSettings(settingsContainer); - - FXUtils.addToPane(resourceTree, container); - FXUtils.addToPane(settingsContainer, container); - FXUtils.addToPane(container, root); - - FXUtils.addClassTo(root, CssClasses.SAVE_AS_DIALOG); - FXUtils.addClassTo(container, CssClasses.DEF_HBOX); - FXUtils.addClassTo(settingsContainer, CssClasses.DEF_GRID_PANE); - } - - /** - * Create settings of the creating file. - * - * @param root the root - */ - @FxThread - protected void createSettings(@NotNull final GridPane root) { - - final Label fileNameLabel = new Label(getFileNameLabelText() + ":"); - fileNameLabel.prefWidthProperty().bind(root.widthProperty().multiply(DEFAULT_LABEL_W_PERCENT)); - - fileNameField = new TextField(); - fileNameField.prefWidthProperty().bind(root.widthProperty()); - fileNameField.textProperty().addListener((observable, oldValue, newValue) -> validateFileName()); - fileNameField.prefWidthProperty().bind(root.widthProperty().multiply(DEFAULT_FIELD_W_PERCENT)); - - root.add(fileNameLabel, 0, 0); - root.add(fileNameField, 1, 0); - - FXUtils.addClassTo(fileNameLabel, CssClasses.DIALOG_DYNAMIC_LABEL); - FXUtils.addClassTo(fileNameField, CssClasses.DIALOG_FIELD); - } - - /** - * Handle the new selected item. - * - * @param newValue the new selected item. - */ - @FxThread - protected void processSelection(@Nullable final TreeItem newValue) { - - if (newValue != null) { - - final TextField fileNameField = getFileNameField(); - - final ResourceElement value = newValue.getValue(); - final Path file = value.getFile(); - - if (!Files.isDirectory(file)) { - fileNameField.setText(FileUtils.getNameWithoutExtension(file)); - } - } - - validateFileName(); - } - - /** - * Validate the inputted name. - */ - @FxThread - protected void validateFileName() { - - final Button okButton = getOkButton(); - if (okButton == null) return; - - final Path fileToCreate = getFileToSave(); - - if (fileToCreate == null) { - okButton.setDisable(true); - return; - } - - okButton.setDisable(false); - } - - /** - * Gets file to create. - * - * @return the file to creating. - */ - @FromAnyThread - protected @Nullable Path getFileToSave() { - - final TextField fileNameField = getFileNameField(); - final String filename = fileNameField.getText(); - if (StringUtils.isEmpty(filename)) return null; - - final String fileExtension = getExtension(); - - final Path selectedFile = getSelectedFile(); - if (selectedFile == null) return null; - - final Path directory = Files.isDirectory(selectedFile) ? selectedFile : selectedFile.getParent(); - - return StringUtils.isEmpty(fileExtension) ? directory.resolve(filename) : - directory.resolve(filename + "." + fileExtension); - } - - /** - * @return the selected file in the resources tree. - */ - @FromAnyThread - private @Nullable Path getSelectedFile() { - - final ResourceTree resourceTree = getResourceTree(); - final MultipleSelectionModel> selectionModel = resourceTree.getSelectionModel(); - final TreeItem selectedItem = selectionModel.getSelectedItem(); - if (selectedItem == null) return null; - - final ResourceElement element = selectedItem.getValue(); - return element.getFile(); - } - - /** - * Get the filename field. - * - * @return the filename field. - */ - @FxThread - protected @NotNull TextField getFileNameField() { - return notNull(fileNameField); - } - - @Override - @FxThread - public void show(@NotNull final Window owner) { - super.show(owner); - - final EditorConfig editorConfig = EditorConfig.getInstance(); - final Path currentAsset = notNull(editorConfig.getCurrentAsset()); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.setOnLoadHandler(finished -> expand(currentAsset, resourceTree, finished)); - resourceTree.fill(currentAsset); - - FX_EVENT_MANAGER.addEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler); - FX_EVENT_MANAGER.addEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle); - FX_EVENT_MANAGER.addEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); - - validateFileName(); - - EXECUTOR_MANAGER.addFxTask(getFileNameField()::requestFocus); - } - - @FxThread - private void expand(@NotNull final Path file, @NotNull final ResourceTree resourceTree, - @NotNull final Boolean finished) { - if (finished) resourceTree.expandTo(file, true); - } - - /** - * Handle creating file event. - */ - @FxThread - private void processEvent(@NotNull final CreatedFileEvent event) { - - final Path file = event.getFile(); - - final Array waitedFilesToSelect = getWaitedFilesToSelect(); - final boolean waitedSelect = waitedFilesToSelect.contains(file); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.notifyCreated(file); - - if (waitedSelect) waitedFilesToSelect.fastRemove(file); - if (waitedSelect || event.isNeedSelect()) resourceTree.expandTo(file, true); - } - - /** - * Handle deleting file event. - */ - @FxThread - private void processEvent(@NotNull final DeletedFileEvent event) { - - final Path file = event.getFile(); - - final ResourceTree resourceTree = getResourceTree(); - resourceTree.notifyDeleted(file); - } - - /** - * Handle selecting file event. - */ - @FxThread - private void processEvent(@NotNull final RequestSelectFileEvent event) { - - final Path file = event.getFile(); - - final ResourceTree resourceTree = getResourceTree(); - final ResourceElement element = createFor(file); - final TreeItem treeItem = findItemForValue(resourceTree.getRoot(), element); - - if (treeItem == null) { - getWaitedFilesToSelect().add(file); - return; - } - - resourceTree.expandTo(treeItem, true); - } - - /** - * @return the list of waited files to select. - */ - @FxThread - private @NotNull Array getWaitedFilesToSelect() { - return waitedFilesToSelect; - } - - @Override - @FxThread - public void hide() { - FX_EVENT_MANAGER.removeEventHandler(CreatedFileEvent.EVENT_TYPE, createdFileHandler); - FX_EVENT_MANAGER.removeEventHandler(RequestSelectFileEvent.EVENT_TYPE, selectFileHandle); - FX_EVENT_MANAGER.removeEventHandler(DeletedFileEvent.EVENT_TYPE, deletedFileHandler); - super.hide(); - } - - /** - * Gets consumer. - * - * @return the function for handling the choose. - */ - @FxThread - protected @NotNull Consumer<@NotNull Path> getConsumer() { - return consumer; - } - - /** - * @return the tree with all resources. - */ - @FxThread - private @NotNull ResourceTree getResourceTree() { - return notNull(resourceTree); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return SAVE_AS_EDITOR_DIALOG_TITLE; - } - - @Override - @FromAnyThread - protected @NotNull Point getSize() { - return DIALOG_SIZE; - } - - @Override - @FromAnyThread - protected @NotNull String getButtonOkText() { - return Messages.SIMPLE_DIALOG_BUTTON_SAVE; - } - - @Override - @FxThread - protected void processOk() { - super.processOk(); - consumer.accept(notNull(getFileToSave())); - } -} diff --git a/src/main/java/com/ss/editor/ui/dialog/sky/CreateEditableSkyDialog.java b/src/main/java/com/ss/editor/ui/dialog/sky/CreateEditableSkyDialog.java deleted file mode 100644 index 1aa2851e..00000000 --- a/src/main/java/com/ss/editor/ui/dialog/sky/CreateEditableSkyDialog.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ss.editor.ui.dialog.sky; - -import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.node.TreeNode; -import org.jetbrains.annotations.NotNull; - -/** - * The dialog to create sky using SS Sky Factory. - * - * @author JavaSaBr - */ -public class CreateEditableSkyDialog extends CreateSkyDialog { - - public CreateEditableSkyDialog(@NotNull final TreeNode parentNode, - @NotNull final NodeTree nodeTree) { - super(parentNode, nodeTree); - } - - @Override - protected boolean isEditableSky() { - return true; - } -} diff --git a/src/main/java/com/ss/editor/ui/event/FxEventManager.java b/src/main/java/com/ss/editor/ui/event/FxEventManager.java deleted file mode 100644 index e9b73ef1..00000000 --- a/src/main/java/com/ss/editor/ui/event/FxEventManager.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.ss.editor.ui.event; - -import static com.ss.rlib.common.util.array.ArrayFactory.newArray; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.manager.ExecutorManager; -import com.ss.rlib.common.util.ClassUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.application.Platform; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.event.EventType; -import org.jetbrains.annotations.NotNull; - -/** - * The class to manage javaFX events. - * - * @author JavaSaBr - */ -public class FxEventManager { - - @NotNull - private static final FxEventManager INSTANCE = new FxEventManager(); - - @FromAnyThread - public static @NotNull FxEventManager getInstance() { - return INSTANCE; - } - - /** - * The table of event handlers. - */ - @NotNull - private final ObjectDictionary, Array>> eventHandlers; - - public FxEventManager() { - this.eventHandlers = DictionaryFactory.newObjectDictionary(); - } - - /** - * Add a new event handler. - * - * @param eventType the event type. - * @param eventHandler the event handler. - */ - @FxThread - public void addEventHandler( - @NotNull EventType eventType, - @NotNull EventHandler eventHandler - ) { - getEventHandlers().get(eventType, () -> newArray(EventHandler.class)) - .add(eventHandler); - } - - /** - * Remove an old event handler. - * - * @param eventType the event type. - * @param eventHandler the event handler. - */ - @FxThread - public void removeEventHandler( - @NotNull EventType eventType, - @NotNull EventHandler eventHandler - ) { - getEventHandlers().getOptional(eventType) - .ifPresent(handlers -> handlers.slowRemove(eventHandler)); - } - - /** - * Get the table of event handlers. - * - * @return the table of event handlers. - */ - @FxThread - private @NotNull ObjectDictionary, Array>> getEventHandlers() { - return eventHandlers; - } - - /** - * Notify about a new event. - * - * @param event the new event. - */ - @FromAnyThread - public void notify(@NotNull Event event) { - if (Platform.isFxApplicationThread()) { - notifyImpl(event); - } else { - var executorManager = ExecutorManager.getInstance(); - executorManager.addFxTask(() -> notifyImpl(event)); - } - } - - /** - * The process of handling a new event. - */ - @FxThread - private void notifyImpl(@NotNull Event event) { - - var eventHandlers = getEventHandlers(); - - for (EventType eventType = event.getEventType(); eventType != null; eventType = eventType.getSuperType()) { - - var handlers = eventHandlers.get(eventType); - if (handlers == null || handlers.isEmpty()) { - continue; - } - - handlers.forEach(event, (handler, toHandle) -> - handler.handle(ClassUtils.unsafeCast(event))); - } - - if (event instanceof ConsumableEvent && !event.isConsumed()) { - var executorManager = ExecutorManager.getInstance(); - executorManager.addFxTask(() -> notifyImpl(event)); - } - } -} diff --git a/src/main/java/com/ss/editor/ui/event/SceneEvent.java b/src/main/java/com/ss/editor/ui/event/SceneEvent.java deleted file mode 100644 index 4d497b26..00000000 --- a/src/main/java/com/ss/editor/ui/event/SceneEvent.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.ss.editor.ui.event; - -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.event.Event; -import javafx.event.EventType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * The base implementation of an event in the javaFX UI. - * - * @author JavaSaBr - */ -public class SceneEvent extends Event { - - private static final long serialVersionUID = 6827900349094865635L; - - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE = new EventType<>(SceneEvent.class.getSimpleName()); - - /** - * The parameters. - */ - @Nullable - private ObjectDictionary values; - - public SceneEvent(@Nullable final Object source, @NotNull final EventType eventType) { - super(source, null, eventType); - } - - public SceneEvent(@NotNull final EventType eventType) { - super(eventType); - } - - /** - * Put the new parameter. - * - * @param key the key. - * @param value the value. - */ - public void set(@NotNull final Object key, @NotNull final Object value) { - - if (values == null) { - values = DictionaryFactory.newObjectDictionary(); - } - - values.put(key, value); - } - - /** - * Remove a value by the key. - * - * @param key the key. - */ - public void remove(@NotNull final Object key) { - if (values == null) return; - values.remove(key); - } - - /** - * Get a value by the key. - * - * @param the type parameter - * @param key the key. - * @return the value or null. - */ - public @Nullable T get(@NotNull final Object key) { - if (values == null) return null; - final Object object = values.get(key); - if (object == null) return null; - return unsafeCast(object); - } -} diff --git a/src/main/java/com/ss/editor/ui/event/impl/RequestedConvertFileEvent.java b/src/main/java/com/ss/editor/ui/event/impl/RequestedConvertFileEvent.java deleted file mode 100644 index d81e37bb..00000000 --- a/src/main/java/com/ss/editor/ui/event/impl/RequestedConvertFileEvent.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.ui.event.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.file.converter.FileConverterDescription; -import com.ss.editor.ui.event.SceneEvent; -import javafx.event.Event; -import javafx.event.EventType; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The event about request to covert a file. - * - * @author JavaSaBr - */ -public class RequestedConvertFileEvent extends SceneEvent { - - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE; - - static { - synchronized (Event.class) { - EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedConvertFileEvent.class.getSimpleName()); - } - } - - private static final String FILE = "file"; - private static final String CONVERTER = "converter"; - - public RequestedConvertFileEvent() { - super(EVENT_TYPE); - } - - /** - * Get the description. - * - * @return the converter description. - */ - public @NotNull FileConverterDescription getDescription() { - return notNull(get(CONVERTER)); - } - - /** - * Set the description. - * - * @param description the converter description. - */ - public void setDescription(@NotNull final FileConverterDescription description) { - set(CONVERTER, description); - } - - /** - * Get the file. - * - * @return the file to convert. - */ - public @NotNull Path getFile() { - return notNull(get(FILE)); - } - - /** - * Set the file. - * - * @param file the file to convert. - */ - public void setFile(@NotNull final Path file) { - set(FILE, file); - } -} diff --git a/src/main/java/com/ss/editor/ui/event/impl/RequestedCreateFileEvent.java b/src/main/java/com/ss/editor/ui/event/impl/RequestedCreateFileEvent.java deleted file mode 100644 index 4711522f..00000000 --- a/src/main/java/com/ss/editor/ui/event/impl/RequestedCreateFileEvent.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ss.editor.ui.event.impl; - -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.ui.event.SceneEvent; -import javafx.event.Event; -import javafx.event.EventType; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; - -/** - * The event about request to create a new file. - * - * @author JavaSaBr - */ -public class RequestedCreateFileEvent extends SceneEvent { - - /** - * The constant EVENT_TYPE. - */ - @NotNull - public static final EventType EVENT_TYPE; - - static { - synchronized (Event.class) { - EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedCreateFileEvent.class.getSimpleName()); - } - } - - private static final String FILE = "file"; - private static final String CREATOR = "creator"; - - public RequestedCreateFileEvent() { - super(EVENT_TYPE); - } - - /** - * Get the description. - * - * @return the creator description. - */ - public @NotNull FileCreatorDescription getDescription() { - return notNull(get(CREATOR)); - } - - /** - * Set the description. - * - * @param description the creator description. - */ - public void setDescription(@NotNull final FileCreatorDescription description) { - set(CREATOR, description); - } - - /** - * Get the file. - * - * @return the file. - */ - public @NotNull Path getFile() { - return notNull(get(FILE)); - } - - /** - * Set the file. - * - * @param file the file. - */ - public void setFile(@NotNull final Path file) { - set(FILE, file); - } -} diff --git a/src/main/java/com/ss/editor/ui/event/impl/RequestedRefreshAssetEvent.java b/src/main/java/com/ss/editor/ui/event/impl/RequestedRefreshAssetEvent.java deleted file mode 100644 index e4667431..00000000 --- a/src/main/java/com/ss/editor/ui/event/impl/RequestedRefreshAssetEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ss.editor.ui.event.impl; - -import com.ss.editor.ui.event.SceneEvent; -import javafx.event.Event; -import javafx.event.EventType; - -/** - * The event about request to refresh the current asset folder. - * - * @author JavaSaBr - */ -public class RequestedRefreshAssetEvent extends SceneEvent { - - /** - * The constant EVENT_TYPE. - */ - public static final EventType EVENT_TYPE; - - static { - synchronized (Event.class) { - EVENT_TYPE = new EventType<>(SceneEvent.EVENT_TYPE, RequestedRefreshAssetEvent.class.getSimpleName()); - } - } - - public RequestedRefreshAssetEvent() { - super(EVENT_TYPE); - } -} diff --git a/src/main/java/com/ss/editor/ui/preview/FilePreviewFactoryRegistry.java b/src/main/java/com/ss/editor/ui/preview/FilePreviewFactoryRegistry.java deleted file mode 100644 index 159e882c..00000000 --- a/src/main/java/com/ss/editor/ui/preview/FilePreviewFactoryRegistry.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ss.editor.ui.preview; - -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.ui.preview.impl.DefaultFilePreviewFactory; -import com.ss.rlib.common.util.ArrayUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import com.ss.rlib.common.util.array.ConcurrentArray; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * The registry with available factories of file previews. - * - * @author JavaSaBr - */ -public class FilePreviewFactoryRegistry { - - @NotNull - private static final FilePreviewFactoryRegistry INSTANCE = new FilePreviewFactoryRegistry(); - - public static @NotNull FilePreviewFactoryRegistry getInstance() { - return INSTANCE; - } - - /** - * The list of available factories. - */ - @NotNull - private final ConcurrentArray factories; - - private FilePreviewFactoryRegistry() { - this.factories = ArrayFactory.newConcurrentAtomicARSWLockArray(FilePreviewFactory.class); - register(DefaultFilePreviewFactory.getInstance()); - } - - /** - * Register the new factory. - * - * @param factory the factory. - */ - @FromAnyThread - public void register(@NotNull final FilePreviewFactory factory) { - ArrayUtils.runInWriteLock(factories, factory, Collection::add); - } - - /** - * Create available of file previews. - * - * @return the list of available file previews. - */ - @FxThread - public Array createAvailablePreviews() { - - final Array result = ArrayFactory.newArray(FilePreview.class); - - ArrayUtils.runInReadLock(factories, result, (previewFactories, toStore) -> - previewFactories.forEach(toStore, FilePreviewFactory::createFilePreviews)); - - result.sort((first, second) -> second.getOrder() - first.getOrder()); - - return result; - } -} diff --git a/src/main/java/com/ss/editor/ui/util/UiUtils.java b/src/main/java/com/ss/editor/ui/util/UiUtils.java deleted file mode 100644 index ef4d2d39..00000000 --- a/src/main/java/com/ss/editor/ui/util/UiUtils.java +++ /dev/null @@ -1,1006 +0,0 @@ -package com.ss.editor.ui.util; - -import static com.ss.editor.util.EditorUtil.getFxScene; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static java.lang.Math.min; -import com.jme3.math.ColorRGBA; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.model.UObject; -import com.ss.editor.ui.component.ScreenComponent; -import com.ss.editor.ui.dialog.asset.file.AssetEditorDialog; -import com.ss.editor.ui.dialog.asset.file.FileAssetEditorDialog; -import com.ss.editor.ui.dialog.asset.file.FolderAssetEditorDialog; -import com.ss.editor.ui.dialog.asset.virtual.StringVirtualAssetEditorDialog; -import com.ss.editor.ui.dialog.save.SaveAsEditorDialog; -import com.ss.rlib.common.util.FileUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.array.ArrayFactory; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.BooleanPropertyBase; -import javafx.beans.value.ChangeListener; -import javafx.collections.ObservableList; -import javafx.css.PseudoClass; -import javafx.event.EventTarget; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.control.*; -import javafx.scene.input.*; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; -import javafx.util.Duration; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.reactfx.util.TriConsumer; - -import java.io.File; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; - -/** - * The utility class with utility UI methods. - * - * @author JavaSaBr - */ -public abstract class UiUtils { - - @NotNull - private static final PseudoClass FOCUSED_PSEUDO_CLASS = PseudoClass.getPseudoClass("focused"); - - @NotNull - private static final Duration TOOLTIP_HIDE_DELAY = new Duration(100); - - @NotNull - private static final Duration TOOLTIP_SHOW_DELAY = new Duration(1000); - - @NotNull - private static final Duration TOOLTIP_SHOW_DURATION = new Duration(5000); - - /** - * Add binding pseudo focus of the pane to focus state of the controls. - * - * @param pane the pane. - * @param controls the controls. - */ - @FxThread - public static @NotNull BooleanProperty addFocusBinding(@NotNull Pane pane, @NotNull Control... controls) { - - var focused = new BooleanPropertyBase(true) { - - @Override - public void invalidated() { - pane.pseudoClassStateChanged(FOCUSED_PSEUDO_CLASS, get()); - } - - @Override - public Object getBean() { - return pane; - } - - @Override - public String getName() { - return "focused"; - } - }; - - ChangeListener listener = (observable, oldValue, newValue) -> { - focused.setValue(newValue || Arrays.stream(controls) - .anyMatch(Node::isFocused)); - }; - - for (var control : controls) { - control.focusedProperty().addListener(listener); - control.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> control.requestFocus()); - } - - focused.setValue(Arrays.stream(controls) - .anyMatch(Node::isFocused)); - - return focused; - } - - /** - * Clear children of a pane. - * - * @param pane the pane. - */ - @FxThread - public static void clear(@NotNull final Pane pane) { - final ObservableList children = pane.getChildren(); - children.forEach(UiUtils::unbind); - children.clear(); - } - - /** - * Unbind a node. - * - * @param node the node. - */ - @FxThread - private static void unbind(@NotNull final Node node) { - if (node instanceof Control) { - final Control control = (Control) node; - control.prefWidthProperty().unbind(); - control.prefHeightProperty().unbind(); - } else if (node instanceof Pane) { - final Pane pane = (Pane) node; - pane.prefHeightProperty().unbind(); - pane.prefWidthProperty().unbind(); - } - } - - /** - * Fill a list of components. - * - * @param container the container - * @param node the node - */ - @FxThread - public static void fillComponents(@NotNull final Array container, @NotNull final Node node) { - - if (node instanceof ScreenComponent) { - container.add((ScreenComponent) node); - } - - if (node instanceof SplitPane) { - final ObservableList items = ((SplitPane) node).getItems(); - items.forEach(child -> fillComponents(container, child)); - } else if (node instanceof TabPane) { - final ObservableList tabs = ((TabPane) node).getTabs(); - tabs.forEach(tab -> fillComponents(container, tab.getContent())); - } - - if (!(node instanceof Parent)) { - return; - } - - final ObservableList nodes = ((Parent) node).getChildrenUnmodifiable(); - nodes.forEach(child -> fillComponents(container, child)); - } - - /** - * Find all components for a type. - * - * @param the type parameter - * @param node the node - * @param type the type - * @return the array - */ - @FxThread - public static @NotNull Array fillComponents(@NotNull final Node node, @NotNull final Class type) { - final Array container = ArrayFactory.newArray(type); - fillComponents(container, node, type); - return container; - } - - /** - * Find all components for a type. - * - * @param the type parameter - * @param container the container - * @param node the node - * @param type the type - */ - @FxThread - public static void fillComponents(@NotNull final Array container, @NotNull final Node node, - @NotNull final Class type) { - - if (type.isInstance(container)) { - container.add(type.cast(node)); - } - - if (!(node instanceof Parent)) { - return; - } - - final ObservableList nodes = ((Parent) node).getChildrenUnmodifiable(); - nodes.forEach(child -> fillComponents(container, child, type)); - } - - /** - * Get all elements of a menu. - * - * @param menuBar the menu bar - * @return the all items - */ - @FxThread - public static @NotNull Array getAllItems(@NotNull final MenuBar menuBar) { - - final Array container = ArrayFactory.newArray(MenuItem.class); - - final ObservableList menus = menuBar.getMenus(); - menus.forEach(menu -> getAllItems(container, menu)); - - return container; - } - - /** - * Collect all elements of a menu. - */ - @FxThread - private static void getAllItems(@NotNull final Array container, @NotNull final MenuItem menuItem) { - - container.add(menuItem); - - if (!(menuItem instanceof Menu)) { - return; - } - - final ObservableList items = ((Menu) menuItem).getItems(); - items.forEach(subMenuItem -> getAllItems(container, subMenuItem)); - } - - /** - * Collect all items. - * - * @param container the container - * @param menuButton the menu button - */ - @FxThread - public static void getAllItems(@NotNull final Array container, @NotNull final MenuButton menuButton) { - final ObservableList items = menuButton.getItems(); - items.forEach(subMenuItem -> getAllItems(container, subMenuItem)); - } - - /** - * Add to. - * - * @param item the item - * @param parent the parent - */ - @FxThread - public static void addTo(@NotNull final TreeItem item, - @NotNull final TreeItem parent) { - final ObservableList> children = parent.getChildren(); - children.add(item); - } - - /** - * Update behaviour of the tooltip. - * - * @param tooltip the tooltip. - * @return the updated tooltip. - */ - @FxThread - public static T updateTooltip(final T tooltip) { - tooltip.setHideDelay(TOOLTIP_HIDE_DELAY); - tooltip.setShowDelay(TOOLTIP_SHOW_DELAY); - tooltip.setShowDuration(TOOLTIP_SHOW_DURATION); - return tooltip; - } - - /** - * Find a tree item by object id. - * - * @param the type parameter - * @param treeView the tree. - * @param objectId the object id. - * @return the tree item or null. - */ - @FxThread - public static @Nullable TreeItem findItem(@NotNull final TreeView treeView, final long objectId) { - return findItem(treeView.getRoot(), objectId); - } - - /** - * Find a tree item by object id. - * - * @param the type parameter - * @param root the root item. - * @param objectId the object id. - * @return the tree item or null. - */ - @FxThread - public static @Nullable TreeItem findItem(@NotNull final TreeItem root, final long objectId) { - - final T value = root.getValue(); - - if (value instanceof UObject && ((UObject) value).getObjectId() == objectId) { - return root; - } - - final ObservableList> children = root.getChildren(); - - if (!children.isEmpty()) { - for (final TreeItem treeItem : children) { - final TreeItem result = findItem(treeItem, objectId); - if (result != null) return result; - } - } - - return null; - } - - /** - * Find a tree item by its value. - * - * @param the type parameter - * @param treeView the tree view. - * @param object the value. - * @return the tree item or null. - */ - @FxThread - public static @Nullable TreeItem findItemForValue(@NotNull final TreeView treeView, @Nullable final Object object) { - return findItemForValue(treeView.getRoot(), object); - } - - /** - * Find a tree item by its value. - * - * @param the type parameter - * @param root the root item. - * @param object the value. - * @return the tree item or null. - */ - @FxThread - public @Nullable static TreeItem findItemForValue(@NotNull final TreeItem root, @Nullable final Object object) { - - if (object == null) { - return null; - } else if (Objects.equals(root.getValue(), object)) { - return root; - } - - final ObservableList> children = root.getChildren(); - - if (!children.isEmpty()) { - for (final TreeItem treeItem : children) { - final TreeItem result = findItemForValue(treeItem, object); - if (result != null) { - return result; - } - } - } - - return null; - } - - /** - * Get all elements of a tree view. - * - * @param the type parameter - * @param treeView the tree view. - * @return the list of all items. - */ - @FxThread - public static @NotNull Array> getAllItems(@NotNull final TreeView treeView) { - - final Array> container = ArrayFactory.newArray(TreeItem.class); - - final TreeItem root = treeView.getRoot(); - final ObservableList> children = root.getChildren(); - - for (final TreeItem child : children) { - collectAllItems(container, child); - } - - return container; - } - - /** - * Visit all items. - * - * @param the type parameter. - * @param item the tree item. - * @param visitor the visitor. - */ - @FxThread - public static void visit(@NotNull final TreeItem item, @NotNull final Consumer> visitor) { - visitor.accept(item); - - final ObservableList> children = item.getChildren(); - if (children.isEmpty()) return; - - for (final TreeItem child : children) { - visit(child, visitor); - } - } - - /** - * Visit all items. - * - * @param the type parameter. - * @param item the tree item. - * @param visitor the visitor. - * @return true of we can visit child elements. - */ - @FxThread - public static boolean visitUntil(@NotNull final TreeItem item, - @NotNull final Predicate> visitor) { - - if (!visitor.test(item)) return false; - - final ObservableList> children = item.getChildren(); - if (children.isEmpty()) return true; - - for (final TreeItem child : children) { - if (!visitUntil(child, visitor)) return false; - } - - return true; - } - - /** - * Collect all elements of tree items. - * - * @param the type parameter - * @param root the tree item. - * @return the list with all items. - */ - @FxThread - public static Array> getAllItems(@NotNull TreeItem root) { - final Array> container = ArrayFactory.newArray(TreeItem.class); - collectAllItems(container, root); - return container; - } - - /** - * Collect all elements of tree items. - * - * @param the type parameter - * @param root the tree item. - * @return the list with all items. - */ - @FxThread - public static Stream> allItems(@NotNull TreeItem root) { - Array> container = ArrayFactory.newArray(TreeItem.class); - collectAllItems(container, root); - return container.stream(); - } - - /** - * Collect all elements of tree items. - * - * @param the type parameter - * @param container the container. - * @param root the tree item. - */ - @FxThread - public static void collectAllItems(@NotNull final Array> container, @NotNull final TreeItem root) { - - container.add(root); - - final ObservableList> children = root.getChildren(); - - for (final TreeItem child : children) { - collectAllItems(container, child); - } - } - - /** - * Convert a color from {@link Color} to {@link ColorRGBA}. - * - * @param color the color - * @return the jme color - */ - @FxThread - public static @Nullable ColorRGBA from(@Nullable final Color color) { - if (color == null) return null; - return new ColorRGBA((float) color.getRed(), (float) color.getGreen(), - (float) color.getBlue(), (float) color.getOpacity()); - } - - /** - * Convert a color from {@link ColorRGBA} to {@link Color}. - * - * @param color the color - * @return the FX color - */ - @FxThread - public static @Nullable Color from(@Nullable final ColorRGBA color) { - if (color == null) return null; - - final float red = min(color.getRed(), 1F); - final float green = min(color.getGreen(), 1F); - final float blue = min(color.getBlue(), 1F); - final float alpha = min(color.getAlpha(), 1F); - - return new Color(red, green, blue, alpha); - } - - /** - * @param event the event. - * @return true if the event is not hotkey. - */ - @FxThread - public static boolean isNotHotKey(@Nullable final KeyEvent event) { - if (event == null) return false; - - final String text = event.getText(); - if (text.isEmpty()) return false; - - final KeyCode code = event.getCode(); - final EventTarget target = event.getTarget(); - - if (code == KeyCode.TAB && !(target instanceof TextInputControl)) { - return false; - } - - if (event.isControlDown()) { - return false; - } else return !event.isShiftDown(); - } - - /** - * Consume an event if the condition returns true. - * - * @param event the event. - * @param condition the condition. - */ - @FxThread - public static void consumeIf(@NotNull final KeyEvent event, @NotNull final Predicate condition) { - if (condition.test(event)) { - event.consume(); - } - } - - /** - * Consume an event if the event is not hotkey. - * - * @param event the event. - */ - @FxThread - public static void consumeIfIsNotHotKey(@Nullable final KeyEvent event) { - - if (event == null) { - return; - } - - final KeyCode code = event.getCode(); - if (code == KeyCode.ESCAPE || code == KeyCode.ENTER) { - return; - } - - if (isNotHotKey(event)) { - event.consume(); - } - } - - /** - * Update an edited cell. - * - * @param cell the edited cell. - */ - @FxThread - public static void updateEditedCell(final Labeled cell) { - - final javafx.scene.Node graphic = cell.getGraphic(); - - if (graphic instanceof HBox) { - final HBox hbox = (HBox) graphic; - hbox.setAlignment(Pos.CENTER_LEFT); - hbox.setMinHeight(cell.getMinHeight()); - } - } - - /** - * Open an resource asset dialog. - * - * @param handler the result handler. - * @param resources the resources. - */ - @FxThread - public static void openResourceAssetDialog(@NotNull final Consumer handler, - @NotNull final Array resources) { - openResourceAssetDialog(handler, null, resources); - } - - /** - * Open an resource asset dialog. - * - * @param handler the result handler. - * @param validator the validator. - * @param resources the resources. - */ - @FxThread - public static void openResourceAssetDialog(@NotNull final Consumer handler, - @Nullable final Function validator, - @NotNull final Array resources) { - final StringVirtualAssetEditorDialog dialog = new StringVirtualAssetEditorDialog(handler, validator, resources); - dialog.show(); - } - - /** - * Open an asset dialog. - * - * @param handler the result handler. - * @param extensions the extensions list. - * @param actionTester the action tester. - */ - @FxThread - public static void openFileAssetDialog(@NotNull final Consumer handler, - @NotNull final Array extensions, - @Nullable final Predicate> actionTester) { - - final AssetEditorDialog dialog = new FileAssetEditorDialog(handler); - dialog.setExtensionFilter(extensions); - dialog.setActionTester(actionTester); - dialog.show(); - } - - /** - * Open an asset dialog. - * - * @param handler the result handler. - * @param actionTester the action tester. - */ - @FxThread - public static void openFolderAssetDialog(@NotNull final Consumer handler, - @Nullable final Predicate> actionTester) { - - final AssetEditorDialog dialog = new FolderAssetEditorDialog(handler); - dialog.setActionTester(actionTester); - dialog.show(); - } - - /** - * Open a save as dialog. - * - * @param handler the result handler. - * @param extension the file extension. - * @param actionTester the action tester. - */ - @FxThread - public static void openSaveAsDialog(@NotNull final Consumer<@NotNull Path> handler, @NotNull final String extension, - @Nullable final Predicate<@NotNull Class> actionTester) { - - final SaveAsEditorDialog dialog = new SaveAsEditorDialog(handler); - dialog.setExtension(extension); - - if (actionTester != null) { - dialog.setActionTester(actionTester); - } - - dialog.show(); - } - - /** - * Accept a drag event if it has a file with required extensions. - * - * @param dragEvent the drag event. - * @param extensions the extensions. - */ - @FxThread - public static void acceptIfHasFile(@NotNull final DragEvent dragEvent, @NotNull final Array extensions) { - - final Dragboard dragboard = dragEvent.getDragboard(); - if (!isHasFile(dragboard, extensions)) return; - - final Set transferModes = dragboard.getTransferModes(); - final boolean isCopy = transferModes.contains(TransferMode.COPY); - - dragEvent.acceptTransferModes(isCopy ? TransferMode.COPY : TransferMode.MOVE); - dragEvent.consume(); - } - - /** - * Accept a drag event if it has a file with required extension. - * - * @param dragEvent the drag event. - * @param targetExtension the extension. - */ - @FxThread - public static void acceptIfHasFile(@NotNull final DragEvent dragEvent, @NotNull final String targetExtension) { - - final Dragboard dragboard = dragEvent.getDragboard(); - if (!isHasFile(dragboard, targetExtension)) return; - - final Set transferModes = dragboard.getTransferModes(); - final boolean isCopy = transferModes.contains(TransferMode.COPY); - - dragEvent.acceptTransferModes(isCopy ? TransferMode.COPY : TransferMode.MOVE); - dragEvent.consume(); - } - - - /** - * Check the dragboard. - * - * @param dragboard the dragboard. - * @param extensions the extensions. - * @return true if there are required file. - */ - @FxThread - public static boolean isHasFile(@NotNull final Dragboard dragboard, @NotNull final Array extensions) { - - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return false; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), true); - - return extensions.contains(extension); - } - - /** - * Check the dragboard. - * - * @param dragboard the dragboard. - * @param targetExtension the target extension. - * @return true if there are required file. - */ - @FxThread - public static boolean isHasFile(@NotNull final Dragboard dragboard, @NotNull final String targetExtension) { - - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return false; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), true); - - return targetExtension.equalsIgnoreCase(extension); - } - - /** - * Handle a first dropped file if it has required extensions. - * - * @param dragEvent the drag event. - * @param extensions the extensions. - * @param handler the handler. - */ - @FxThread - public static void handleDroppedFile(@NotNull final DragEvent dragEvent, @NotNull final Array extensions, - @NotNull final Consumer handler) { - - final Dragboard dragboard = dragEvent.getDragboard(); - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), true); - - if (!extensions.contains(extension)) { - return; - } - - handler.accept(file.toPath()); - } - - /** - * Handle a first dropped file if it has required extensions. - * - * @param the type parameter - * @param dragEvent the drag event. - * @param extensions the extensions. - * @param firstArg the first argument. - * @param handler the handler. - */ - @FxThread - public static void handleDroppedFile(@NotNull final DragEvent dragEvent, - @NotNull final Array extensions, @NotNull final F firstArg, - @NotNull final BiConsumer handler) { - - final Dragboard dragboard = dragEvent.getDragboard(); - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), true); - - if (!extensions.contains(extension)) { - return; - } - - handler.accept(firstArg, file.toPath()); - } - - /** - * Handle a first dropped file if it has required extensions. - * - * @param the type parameter - * @param the type parameter - * @param dragEvent the drag event. - * @param targetExtension the extension. - * @param firstArg the first argument. - * @param secondArg the second argument. - * @param handler the handler. - */ - @FxThread - public static void handleDroppedFile(@NotNull final DragEvent dragEvent, - @NotNull final String targetExtension, @NotNull final F firstArg, - @NotNull final S secondArg, - @NotNull final TriConsumer handler) { - - handleDroppedFile(dragEvent.getDragboard(), targetExtension, firstArg, secondArg, handler); - } - - /** - * Handle a first dropped file if it has required extensions. - * - * @param the type parameter - * @param the type parameter - * @param dragboard the dragboard. - * @param targetExtension the extension. - * @param firstArg the first argument. - * @param secondArg the second argument. - * @param handler the handler. - */ - @FxThread - public static void handleDroppedFile(@NotNull final Dragboard dragboard, - @NotNull final String targetExtension, @NotNull final F firstArg, - @NotNull final S secondArg, - @NotNull final TriConsumer handler) { - - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), false); - - if (!targetExtension.equalsIgnoreCase(extension)) { - return; - } - - handler.accept(firstArg, secondArg, file.toPath()); - } - - /** - * Handle a first dropped file if it has required extensions. - * - * @param the type parameter - * @param the type parameter - * @param dragEvent the drag event. - * @param extensions the extensions. - * @param firstArg the first argument. - * @param secondArg the second argument. - * @param handler the handler. - */ - @FxThread - public static void handleDroppedFile(@NotNull final DragEvent dragEvent, - @NotNull final Array extensions, @NotNull final F firstArg, - @NotNull final S secondArg, - @NotNull final TriConsumer handler) { - - final Dragboard dragboard = dragEvent.getDragboard(); - final List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - - if (files == null || files.size() != 1) { - return; - } - - final File file = files.get(0); - final String extension = FileUtils.getExtension(file.getName(), true); - - if (!extensions.contains(extension)) { - return; - } - - handler.accept(firstArg, secondArg, file.toPath()); - } - - - /** - * Convert the color to hex presentation to use in web. - * - * @param color the color. - * @return the web presentation. - */ - @FromAnyThread - public static @NotNull String toWeb(@NotNull final Color color) { - final int red = (int) (color.getRed() * 255); - final int green = (int) (color.getGreen() * 255); - final int blue = (int) (color.getBlue() * 255); - return "#" + Integer.toHexString(red) + Integer.toHexString(green) + Integer.toHexString(blue); - } - - /** - * Increment the loading counter. - */ - @FxThread - public static void incrementLoading() { - getFxScene().incrementLoading(); - } - - /** - * Decrement the loading counter. - */ - @FxThread - public static void decrementLoading() { - getFxScene().decrementLoading(); - } - - /** - * Create a dialog for showing the exception. - */ - @FxThread - public static @NotNull Alert createErrorAlert(@NotNull final Exception e, @Nullable final String localizedMessage, - @Nullable final String stackTrace) { - - final TextArea textArea = new TextArea(stackTrace); - textArea.setEditable(false); - textArea.setWrapText(true); - - VBox.setMargin(textArea, new Insets(2, 5, 2, 5)); - - final Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText(StringUtils.isEmpty(localizedMessage) ? e.getClass().getSimpleName() : localizedMessage); - - final DialogPane dialogPane = alert.getDialogPane(); - dialogPane.setExpandableContent(new VBox(textArea)); - dialogPane.expandedProperty().addListener((observable, oldValue, newValue) -> { - - if (newValue == Boolean.TRUE) { - alert.setWidth(800); - alert.setHeight(400); - } else { - alert.setWidth(500); - alert.setHeight(220); - } - }); - - return alert; - } - - /** - * Check of existing a file in clipboard. - * - * @return true if you have a file in your system clipboard. - */ - @FxThread - public static boolean hasFileInClipboard() { - final Clipboard clipboard = Clipboard.getSystemClipboard(); - if (clipboard == null) return false; - final List files = unsafeCast(clipboard.getContent(DataFormat.FILES)); - return !(files == null || files.isEmpty()); - } - - /** - * Find a menu item by the item's type. - * - * @param items the item list. - * @param type the item's type. - * @param the item's type. - * @return the found item or null. - */ - @FxThread - public static @Nullable T findMenuItem(@NotNull final List items, - @NotNull final Class type) { - for (final MenuItem item : items) { - - if (type.isInstance(item)) { - return type.cast(item); - } - - if (item instanceof Menu) { - final T result = findMenuItem(((Menu) item).getItems(), type); - if (result != null) { - return result; - } - } - } - - return null; - } - - private UiUtils() { - throw new RuntimeException(); - } -} diff --git a/src/main/java/com/ss/editor/util/AudioNodeUtils.java b/src/main/java/com/ss/editor/util/AudioNodeUtils.java deleted file mode 100644 index 253cb5ae..00000000 --- a/src/main/java/com/ss/editor/util/AudioNodeUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ss.editor.util; - -import com.jme3.audio.AudioData; -import com.jme3.audio.AudioKey; -import com.jme3.audio.AudioNode; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.JmeThread; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; - -/** - * The utility class to work with audio nodes. - * - * @author JavaSaBr - */ -public class AudioNodeUtils { - - private static final Field AUDIO_DATA_FIELD; - private static final Field AUDIO_KEY_FIELD; - - static { - try { - - AUDIO_KEY_FIELD = AudioNode.class.getDeclaredField("audioKey"); - AUDIO_KEY_FIELD.setAccessible(true); - - AUDIO_DATA_FIELD = AudioNode.class.getDeclaredField("data"); - AUDIO_DATA_FIELD.setAccessible(true); - - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - - /** - * Update audio data for an audio node. - * - * @param audioNode the audio node. - * @param audioData the audio data. - * @param audioKey the audio key. - */ - @JmeThread - public static void updateData( - @NotNull AudioNode audioNode, - @Nullable AudioData audioData, - @Nullable AudioKey audioKey - ) { - try { - AUDIO_DATA_FIELD.set(audioNode, audioData); - AUDIO_KEY_FIELD.set(audioNode, audioKey); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Get an audio key from the audio node. - * - * @param audioNode the audio node. - * @return the audio key. - */ - @FromAnyThread - public static @Nullable AudioKey getAudioKey(@NotNull AudioNode audioNode) { - try { - return (AudioKey) AUDIO_KEY_FIELD.get(audioNode); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/com/ss/editor/util/EditorUtil.java b/src/main/java/com/ss/editor/util/EditorUtil.java deleted file mode 100644 index 819485ac..00000000 --- a/src/main/java/com/ss/editor/util/EditorUtil.java +++ /dev/null @@ -1,1043 +0,0 @@ -package com.ss.editor.util; - -import static com.ss.rlib.common.util.ClassUtils.cast; -import static com.ss.rlib.common.util.ClassUtils.unsafeCast; -import static com.ss.rlib.common.util.ObjectUtils.notNull; -import static java.lang.Math.acos; -import static java.lang.Math.toDegrees; -import static java.lang.ThreadLocal.withInitial; -import static java.util.stream.Collectors.toList; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.jme3.environment.generation.JobProgressAdapter; -import com.jme3.input.InputManager; -import com.jme3.light.LightProbe; -import com.jme3.material.Material; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.post.FilterPostProcessor; -import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.system.JmeSystem; -import com.jme3.system.Platform; -import com.ss.editor.JfxApplication; -import com.ss.editor.JmeApplication; -import com.ss.editor.analytics.google.GAnalytics; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.annotation.FxThread; -import com.ss.editor.annotation.JmeThread; -import com.ss.editor.config.EditorConfig; -import com.ss.editor.extension.scene.SceneLayer; -import com.ss.editor.manager.ClasspathManager; -import com.ss.editor.manager.ExecutorManager; -import com.ss.editor.manager.ResourceManager; -import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.model.undo.editor.SceneChangeConsumer; -import com.ss.editor.ui.event.FxEventManager; -import com.ss.editor.ui.event.impl.RequestedOpenFileEvent; -import com.ss.editor.ui.scene.EditorFxScene; -import com.ss.editor.ui.util.UiUtils; -import com.ss.rlib.common.logging.Logger; -import com.ss.rlib.common.logging.LoggerManager; -import com.ss.rlib.common.util.ClassUtils; -import com.ss.rlib.common.util.StringUtils; -import com.ss.rlib.common.util.array.Array; -import com.ss.rlib.common.util.dictionary.DictionaryFactory; -import com.ss.rlib.common.util.dictionary.ObjectDictionary; -import javafx.application.HostServices; -import javafx.scene.input.ClipboardContent; -import javafx.scene.input.DataFormat; -import javafx.scene.input.Dragboard; -import javafx.stage.Stage; -import javafx.stage.Window; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.net.MalformedURLException; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * The class with utility methods for the Editor. - * - * @author JavaSaBr - */ -public abstract class EditorUtil { - - private static final Logger LOGGER = LoggerManager.getLogger(EditorUtil.class); - - public static final DataFormat JAVA_PARAM = new DataFormat("jMB.javaParam"); - public static final DataFormat GNOME_FILES = new DataFormat("x-special/gnome-copied-files"); - - private static final ThreadLocal LOCATE_DATE_FORMAT = withInitial(() -> - new SimpleDateFormat("HH:mm:ss:SSS")); - - private static ThreadLocal, Enum[]>> ENUM_VALUES_LOCAL = - ThreadLocal.withInitial(DictionaryFactory::newObjectDictionary); - - private static JmeApplication jmeApplication; - private static JfxApplication jfxApplication; - - public static void setJmeApplication(@NotNull JmeApplication jmeApplication) { - EditorUtil.jmeApplication = jmeApplication; - } - - public static void setJfxApplication(@NotNull JfxApplication jfxApplication) { - EditorUtil.jfxApplication = jfxApplication; - } - - /** - * Get the asset manager. - * - * @return the asset manager. - */ - @FromAnyThread - public static @NotNull AssetManager getAssetManager() { - return jmeApplication.getAssetManager(); - } - - /** - * Get the input manager. - * - * @return the input manager. - */ - @FromAnyThread - public static @NotNull InputManager getInputManager() { - return jmeApplication.getInputManager(); - } - - /** - * Get the render manager. - * - * @return the render manager. - */ - @FromAnyThread - public static @NotNull RenderManager getRenderManager() { - return jmeApplication.getRenderManager(); - } - - /** - * Get the renderer. - * - * @return the renderer. - */ - @FromAnyThread - public static @NotNull Renderer getRenderer() { - return jmeApplication.getRenderer(); - } - - /** - * Get the root node. - * - * @return the root node. - */ - @JmeThread - public static @NotNull Node getGlobalRootNode() { - return jmeApplication.getRootNode(); - } - - /** - * Get the preview node. - * - * @return the preview node. - */ - @JmeThread - public static @NotNull Node getPreviewNode() { - return jmeApplication.getPreviewNode(); - } - - /** - * Get the preview camera. - * - * @return the preview camera. - */ - @JmeThread - public static @NotNull Camera getPreviewCamera() { - return jmeApplication.getPreviewCamera(); - } - - /** - * Get the camera. - * - * @return the camera. - */ - @FromAnyThread - public static @NotNull Camera getGlobalCamera() { - return jmeApplication.getCamera(); - } - - /** - * Get the global filter post processor. - * - * @return the global filter post processor. - */ - @JmeThread - public static @NotNull FilterPostProcessor getGlobalFilterPostProcessor() { - return jmeApplication.getPostProcessor(); - } - - /** - * Get the default material. - * - * @return the default material. - */ - @FromAnyThread - public static @NotNull Material getDefaultMaterial() { - return jmeApplication.getDefaultMaterial(); - } - - /** - * Disable the global PBR light probe. - */ - @JmeThread - public static void disableGlobalLightProbe() { - jmeApplication.disableLightProbe(); - } - - /** - * Enable the global PBR light probe. - */ - @JmeThread - public static void enableGlobalLightProbe() { - jmeApplication.enableLightProbe(); - } - - /** - * Update the light probe. - * - * @param progressAdapter the progress adapter - */ - @JmeThread - public static void updateGlobalLightProbe(@NotNull JobProgressAdapter progressAdapter) { - jmeApplication.updateLightProbe(progressAdapter); - } - - /** - * Get the state manager. - * - * @return the state manager. - */ - @FromAnyThread - public static @NotNull AppStateManager getStateManager() { - return jmeApplication.getStateManager(); - } - - /** - * Gets the last opened window. - * - * @return the last opened window. - */ - @FxThread - public static @NotNull Window getFxLastWindow() { - return jfxApplication.getLastWindow(); - } - - /** - * Get the current JavaFX scene. - * - * @return the JavaFX scene. - */ - @FxThread - public static @NotNull EditorFxScene getFxScene() { - return jfxApplication.getScene(); - } - - /** - * Get the host services. - * - * @return the host services. - */ - @FxThread - public static @NotNull HostServices getHostServices() { - return jfxApplication.getHostServices(); - } - - /** - * Get the current stage of JavaFX. - * - * @return the current stage of JavaFX. - */ - @FxThread - public static @NotNull Stage getFxStage() { - return jfxApplication.getStage(); - } - - /** - * Register the opened new window. - * - * @param window the opened new window. - */ - @FromAnyThread - public static void addFxWindow(@NotNull Window window) { - jfxApplication.addWindow(window); - } - - /** - * Delete the closed window. - * - * @param window the closed window. - */ - @FromAnyThread - public static void removeFxWindow(@NotNull Window window) { - jfxApplication.removeWindow(window); - } - - /** - * Request focus to FX window. - */ - @FxThread - public static void requestFxFocus() { - jfxApplication.requestFocus(); - } - - /** - * Added files like files to copy to clipboard content. - * - * @param paths the list of files. - * @param content the content to store. - */ - @FxThread - public static @NotNull ClipboardContent addCopiedFile( - @NotNull Array paths, - @NotNull ClipboardContent content - ) { - - var files = paths.stream() - .map(Path::toFile) - .collect(toList()); - - content.putFiles(files); - content.put(EditorUtil.JAVA_PARAM, "copy"); - - var platform = JmeSystem.getPlatform(); - - if (platform == Platform.Linux64 || platform == Platform.Linux32) { - - var builder = new StringBuilder("copy\n"); - - paths.forEach(builder, (path, b) -> - b.append(path.toUri().toASCIIString()).append('\n')); - - builder.delete(builder.length() - 1, builder.length()); - - var buffer = ByteBuffer.allocate(builder.length()); - - for (int i = 0, length = builder.length(); i < length; i++) { - buffer.put((byte) builder.charAt(i)); - } - - buffer.flip(); - - content.put(GNOME_FILES, buffer); - } - - return content; - } - - /** - * Check exists boolean. - * - * @param path the path to resource. - * @return true if the resource is exists. - */ - @FromAnyThread - public static boolean checkExists(@NotNull String path) { - var cs = EditorUtil.class; - return cs.getResource(path) != null || cs.getResource("/" + path) != null; - } - - /** - * Check exists boolean. - * - * @param path the path to resource. - * @param classLoader the class loader. - * @return true if the resource is exists. - */ - @FromAnyThread - public static boolean checkExists(@NotNull String path, @NotNull ClassLoader classLoader) { - return classLoader.getResource(path) != null || classLoader.getResource("/" + path) != null; - } - - /** - * Convert classpath path to external path. - * - * @param path the path to resource. - * @param classLoader the class loader. - * @return the external form or null. - */ - @FromAnyThread - public static @Nullable String toExternal(@NotNull String path, @NotNull ClassLoader classLoader) { - - if (!checkExists(path, classLoader)) { - return null; - } - - var resource = classLoader.getResource(path); - if (resource == null) { - resource = classLoader.getResource("/" + path); - } - - return resource == null ? null : resource.toExternalForm(); - } - - /** - * Get the angle between these points. - * - * @param center the center. - * @param first the first point. - * @param second the second point. - * @return the angle between these points. - */ - @FromAnyThread - public static float getAngle( - @NotNull Vector2f center, - @NotNull Vector2f first, - @NotNull Vector2f second - ) { - - var x = center.getX(); - var y = center.getY(); - - var ax = first.getX() - x; - var ay = first.getY() - y; - var bx = second.getX() - x; - var by = second.getY() - y; - - var delta = (float) ((ax * bx + ay * by) / Math.sqrt((ax * ax + ay * ay) * (bx * bx + by * by))); - - if (delta > 1.0) { - return 0.0F; - } else if (delta < -1.0) { - return 180.0F; - } - - return (float) toDegrees(acos(delta)); - } - - /** - * Get an input stream. - * - * @param path the path to resource. - * @return the input stream of the resource or null. - */ - @FromAnyThread - public static @Nullable InputStream getInputStream(@NotNull String path) { - return JfxApplication.class.getResourceAsStream(path); - } - - /** - * Get an input stream or throw an exception. - * - * @param path the path to resource. - * @return the input stream of the resource or null. - */ - @FromAnyThread - public static @NotNull InputStream requireInputStream(@NotNull String path) { - return notNull(JfxApplication.class.getResourceAsStream(path)); - } - - /** - * Get the input stream. - * - * @param path the path to resource. - * @param classLoader the class loader. - * @return the input stream of the resource or null. - */ - @FromAnyThread - public static @Nullable InputStream getInputStream(@NotNull String path, @NotNull ClassLoader classLoader) { - return classLoader.getResourceAsStream(path); - } - - /** - * Get the user name of the computer user. - * - * @return the user name. - */ - @FromAnyThread - public static @NotNull String getUserName() { - return System.getProperty("user.name"); - } - - /** - * Check visibility the position on the screen. - * - * @param position the position for checking. - * @param camera the camera of the screen. - * @return true of we can see the position on the screen. - */ - @FromAnyThread - public static boolean isVisibleOnScreen(@NotNull Vector3f position, @NotNull Camera camera) { - - var maxHeight = camera.getHeight(); - var maxWidth = camera.getWidth(); - - var isBottom = position.getY() < 0; - var isTop = position.getY() > maxHeight; - var isLeft = position.getX() < 0; - var isRight = position.getX() > maxWidth; - - return !isBottom && !isLeft && !isTop && !isRight && position.getZ() < 1F; - } - - /** - * Calculate new point from first point and using second point like a direction. - * - * @param first the first point. - * @param second the second point. - * @param store the container of the result. - * @param length the distance. - */ - @FromAnyThread - public static void movePoint( - @NotNull Vector3f first, - @NotNull Vector3f second, - @NotNull Vector3f store, - int length - ) { - store.x = first.x + (second.x - first.x) * length; - store.y = first.y + (second.y - first.y) * length; - store.z = first.z + (second.z - first.z) * length; - } - - /** - * Convert unix time to string presentation. - * - * @param time the unix time. - * @return the string presentation. - */ - @FromAnyThread - public static @NotNull String timeFormat(long time) { - var format = LOCATE_DATE_FORMAT.get(); - return format.format(new Date(time)); - } - - /** - * Get the path to the file from the asset folder. - * - * @param assetFolder the asset folder. - * @param file the file. - * @return the relative path. - */ - @FromAnyThread - public static @NotNull Path getAssetFile(@NotNull Path assetFolder, @NotNull Path file) { - return assetFolder.relativize(file); - } - - /** - * Get the path to the file from the current asset folder. - * - * @param file the file. - * @return the relative path. - */ - @FromAnyThread - public static @Nullable Path getAssetFile(@NotNull Path file) { - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) { - return null; - } - - try { - return currentAsset.relativize(file); - } catch (IllegalArgumentException e) { - LOGGER.warning("Can't create asset file of the " + file + " for asset folder " + currentAsset); - LOGGER.warning(e); - return null; - } - } - - /** - * Get the absolute path to the file in the current asset. - * - * @param assetFile the file. - * @return the absolute path to the file. - */ - @FromAnyThread - public static @Nullable Path getRealFile(@NotNull Path assetFile) { - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) { - return null; - } - - return currentAsset.resolve(assetFile); - } - - /** - * Get the absolute path to the file in the current asset. - * - * @param assetFile the asset path to file. - * @return the absolute path to the file. - */ - @FromAnyThread - public static @Nullable Path getRealFile(@NotNull String assetFile) { - - var editorConfig = EditorConfig.getInstance(); - var currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) { - return null; - } - - return currentAsset.resolve(assetFile); - } - - /** - * To asset path string. - * - * @param path the path - * @return the valid asset path for the file. - */ - @FromAnyThread - public static @NotNull String toAssetPath(@NotNull Path path) { - - if (File.separatorChar == '/') { - return path.toString(); - } - - return path.toString().replace("\\", "/"); - } - - /** - * Handle exception. - * - * @param logger the logger. - * @param owner the owner. - * @param e the exception. - */ - @FromAnyThread - public static void handleException(@Nullable Logger logger, @Nullable Object owner, @NotNull Exception e) { - handleException(logger, owner, e, null); - } - - /** - * Handle exception. - * - * @param logger the logger. - * @param owner the owner. - * @param e the exception. - * @param callback the callback. - */ - @FromAnyThread - public static void handleException( - @Nullable Logger logger, - @Nullable Object owner, - @NotNull Exception e, - @Nullable Runnable callback - ) { - - if (logger == null) { - logger = LOGGER; - } - - if (owner == null) { - logger.warning(e); - } else { - logger.warning(owner, e); - } - - var executorManager = ExecutorManager.getInstance(); - executorManager.addFxTask(() -> { - - GAnalytics.sendException(e, false); - - var localizedMessage = e.getLocalizedMessage(); - var stackTrace = buildStackTrace(e); - - var alert = UiUtils.createErrorAlert(e, localizedMessage, stackTrace); - alert.show(); - alert.setWidth(500); - alert.setHeight(220); - - if (callback != null) { - alert.setOnHidden(event -> callback.run()); - } - }); - } - - /** - * Build the stack trace of the exception. - * - * @param exception the exception. - * @return the built stack trace. - */ - @FromAnyThread - public static String buildStackTrace(@NotNull Exception exception) { - - var writer = new StringWriter(); - var printWriter = new PrintWriter(writer); - - exception.printStackTrace(printWriter); - - var stackTrace = writer.toString(); - - var level = 0; - - for (var cause = exception.getCause(); cause != null && level < 6; cause = cause.getCause(), level++) { - - writer = new StringWriter(); - printWriter = new PrintWriter(writer); - - cause.printStackTrace(printWriter); - - stackTrace += "\n caused by " + writer.toString(); - } - - return stackTrace; - } - - /** - * Open the file in an external editor. - * - * @param path the path - */ - @FromAnyThread - public static void openFileInExternalEditor(@NotNull Path path) { - - var platform = JmeSystem.getPlatform(); - var commands = new ArrayList(); - - if (platform == Platform.MacOSX64 || platform == Platform.MacOSX_PPC64) { - commands.add("open"); - } else if (platform == Platform.Windows32 || platform == Platform.Windows64) { - commands.add("cmd"); - commands.add("/c"); - commands.add("start"); - } else if (platform == Platform.Linux32|| platform == Platform.Linux64) { - commands.add("xdg-open"); - } - - if (commands.isEmpty()) { - return; - } - - String url; - try { - url = path.toUri().toURL().toString(); - } catch (MalformedURLException e) { - handleException(LOGGER, null, e); - return; - } - - commands.add(url); - - var processBuilder = new ProcessBuilder(); - processBuilder.command(commands); - - try { - processBuilder.start(); - } catch (IOException e) { - handleException(LOGGER, null, e); - } - } - - /** - * Open the file in a system explorer. - * - * @param path the path - */ - @FromAnyThread - public static void openFileInSystemExplorer(@NotNull Path path) { - - var platform = JmeSystem.getPlatform(); - var commands = new ArrayList(); - - if (platform == Platform.MacOSX64 || platform == Platform.MacOSX_PPC64) { - commands.add("open"); - commands.add("-R"); - } else if (platform == Platform.Windows32 || platform == Platform.Windows64) { - commands.add("explorer"); - commands.add("/select,"); - } else if (platform == Platform.Linux32 || platform == Platform.Linux64) { - if (isAppExists("nautilus -v")) { - commands.add("nautilus"); - } else if (isAppExists("dolphin -v")) { - commands.add("dolphin"); - commands.add("--select"); - } else { - commands.add("xdg-open"); - if (!Files.isDirectory(path)) { - path = path.getParent(); - } - } - } - - if (commands.isEmpty()) { - return; - } - - String url; - try { - url = path.toUri().toURL().toString(); - } catch (MalformedURLException e) { - handleException(LOGGER, null, e); - return; - } - - commands.add(url); - - var processBuilder = new ProcessBuilder(); - processBuilder.command(commands); - try { - processBuilder.start(); - } catch (IOException e) { - handleException(LOGGER, null, e); - } - } - - @FromAnyThread - private static boolean isAppExists(@NotNull String command) { - - var runtime = Runtime.getRuntime(); - int result; - try { - var exec = runtime.exec(command); - result = exec.waitFor(); - } catch (InterruptedException | IOException e) { - return false; - } - - return result >= 0; - } - - /** - * Convert the object to byte array. - * - * @param object the object - * @return the byte array. - */ - @FromAnyThread - public static @NotNull byte[] serialize(@NotNull Serializable object) { - - var bout = new ByteArrayOutputStream(); - - try (var out = new ObjectOutputStream(bout)) { - out.writeObject(object); - } catch (IOException e) { - LOGGER.warning(e); - } - - return bout.toByteArray(); - } - - /** - * Convert the byte array to object. - * - * @param the type parameter - * @param bytes the byte array. - * @return the result object. - */ - @FromAnyThread - public static @NotNull T deserialize(@NotNull byte[] bytes) { - - var bin = new ByteArrayInputStream(bytes); - - try (var in = new ExtObjectInputStream(bin)) { - return unsafeCast(in.readObject()); - } catch (ClassNotFoundException | IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Format the float number. - * - * @param value the value - * @param mod the mod - * @return the float - */ - @FromAnyThread - public static float clipNumber(float value, float mod) { - return (int) (value * mod) / mod; - } - - /** - * Get an array of available enum values by an enum value. - * - * @param the type parameter - * @param value the enum value. - * @return the array of enum values. - */ - @FromAnyThread - public static > @NotNull E[] getAvailableValues(@NotNull E value) { - - var valueClass = value.getClass(); - if (!valueClass.isEnum()) { - throw new RuntimeException("The class " + valueClass + " isn't enum."); - } - - var enumConstants = valueClass.getEnumConstants(); - - return unsafeCast(enumConstants); - } - - /** - * Try to create an user object using asset classpath and additional classpath. - * - * @param the type parameter - * @param owner the requester. - * @param className the classname. - * @param resultType the result type. - * @return the new instance or null. - */ - @FromAnyThread - public static @Nullable T tryToCreateUserObject( - @NotNull Object owner, - @NotNull String className, - @NotNull Class resultType - ) { - - var resourceManager = ResourceManager.getInstance(); - var classpathManager = ClasspathManager.getInstance(); - - Object newExample = null; - try { - newExample = ClassUtils.newInstance(className); - } catch (RuntimeException e) { - - var classLoaders = resourceManager.getClassLoaders(); - - for (var classLoader : classLoaders) { - try { - var targetClass = classLoader.loadClass(className); - newExample = ClassUtils.newInstance(targetClass); - } catch (ClassNotFoundException ex) { - LOGGER.warning(owner, e); - } - } - - var librariesLoader = classpathManager.getLibrariesLoader(); - if (librariesLoader != null) { - try { - var targetClass = librariesLoader.loadClass(className); - newExample = ClassUtils.newInstance(targetClass); - } catch (final ClassNotFoundException ex) { - LOGGER.warning(owner, e); - } - } - } - - return cast(resultType, newExample); - } - - /** - * Get a default layer of the change consumer. - * - * @param consumer the change consumer. - * @return the default layer or null. - */ - @FromAnyThread - public static @Nullable SceneLayer getDefaultLayer(@NotNull ChangeConsumer consumer) { - - if (!(consumer instanceof SceneChangeConsumer)) { - return null; - } - - var sceneNode = ((SceneChangeConsumer) consumer).getCurrentModel(); - var layers = sceneNode.getLayers(); - - if (layers.isEmpty()) { - return null; - } - - return layers.get(0); - } - - /** - * Return true if the asset key is null or empty. - * - * @param assetKey the asset key. - * @return true if the asset key is null or empty. - */ - public static boolean isEmpty(@Nullable AssetKey assetKey) { - return assetKey == null || StringUtils.isEmpty(assetKey.getName()); - } - - /** - * Open the asset resource in an editor. - * - * @param assetKey the asset key. - */ - @FromAnyThread - public static void openInEditor(@Nullable AssetKey assetKey) { - - if (assetKey == null) { - return; - } - - var assetPath = assetKey.getName(); - if (StringUtils.isEmpty(assetPath)) { - return; - } - - var assetFile = Paths.get(assetPath); - var realFile = notNull(getRealFile(assetFile)); - if (!Files.exists(realFile)) { - return; - } - - FxEventManager.getInstance() - .notify(new RequestedOpenFileEvent(realFile)); - } - - /** - * Get the list of files in the current dragboard. - * - * @param dragboard the current dragboard. - * @return the list of files. - */ - @FromAnyThread - public static @NotNull List getFiles(@NotNull Dragboard dragboard) { - List files = unsafeCast(dragboard.getContent(DataFormat.FILES)); - return files == null ? Collections.emptyList() : files; - } - - /** - * Get an array of enum constants by the class. - * - * @param enumType the enum's class. - * @param the enum's type. - * @return the array of enum's constants. - */ - @FromAnyThread - public static T[] getEnumValues(@NotNull Class enumType) { - - if(!enumType.isEnum()) { - throw new IllegalArgumentException("The type " + enumType + " isn't a enum."); - } - - return unsafeCast(ENUM_VALUES_LOCAL.get() - .get(enumType, type -> (Enum[]) type.getEnumConstants())); - } - - /** - * Find a root key of the spatial. - * - * @param spatial the spatial. - * @return the root key or null. - */ - public static @Nullable String findRootKey(@Nullable Spatial spatial) { - - if(spatial == null) { - return null; - } - - return NodeUtils.findParentOpt(spatial, sp -> sp.getKey() != null) - .map(Spatial::getKey) - .map(AssetKey::getName) - .orElse(null); - } -} diff --git a/src/main/resources/app-config.json b/src/main/resources/app-config.json new file mode 100644 index 00000000..357b9055 --- /dev/null +++ b/src/main/resources/app-config.json @@ -0,0 +1,12 @@ +{ + "Graphics.enablePBR": true, + "Graphics.enable3D": true, + "Dev.debug": true, + "Dev.cameraDebug": true, + "Dev.transformsDebug": false, + "Dev.jfxMouseInput": false, + "Dev.jfxKeyInput": false, + "Dev.debugJFX": false, + "Dev.debugStartup": false, + "Dev.debugAsyncEventManager": false +} \ No newline at end of file diff --git a/src/main/resources/app-config.xml b/src/main/resources/app-config.xml deleted file mode 100644 index 69e765f1..00000000 --- a/src/main/resources/app-config.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index 4a71c727..914af46b 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -151,6 +151,7 @@ ModelFileEditorNodePointLight=Point light ModelFileEditorNodeSpotLight=Spot light ModelFileEditorNodeLightProbe=Light probe ModelFileEditorNodeAnimControl=Animation +ModelFileEditorNodeAnimComposer=Animation composer ModelFileEditorNodeParticleEmitterInfluencers=Influencers ModelFileEditorNodeParticleEmitterInfluencerEmpty=Empty influencer ModelFileEditorNodeParticleEmitterInfluencerDefault=Default influencer diff --git a/src/main/resources/messages/messages_de.properties b/src/main/resources/messages/messages_de.properties index 51d53a99..48b77e0f 100644 --- a/src/main/resources/messages/messages_de.properties +++ b/src/main/resources/messages/messages_de.properties @@ -151,6 +151,7 @@ ModelFileEditorNodePointLight=Punktlicht ModelFileEditorNodeSpotLight=Spot-Licht ModelFileEditorNodeLightProbe=Lichtprobe ModelFileEditorNodeAnimControl=Animation +ModelFileEditorNodeAnimComposer=Animation composer ModelFileEditorNodeParticleEmitterInfluencers=Influencer ModelFileEditorNodeParticleEmitterInfluencerEmpty=Leerer Influencer ModelFileEditorNodeParticleEmitterInfluencerDefault=Standard-Influencer diff --git a/src/main/resources/messages/messages_fr.properties b/src/main/resources/messages/messages_fr.properties index b93d42cf..c309d947 100644 --- a/src/main/resources/messages/messages_fr.properties +++ b/src/main/resources/messages/messages_fr.properties @@ -151,6 +151,7 @@ ModelFileEditorNodePointLight=Lumière ponctuelle ModelFileEditorNodeSpotLight=Spot ModelFileEditorNodeLightProbe=Sonde lumineuse ModelFileEditorNodeAnimControl=Animation +ModelFileEditorNodeAnimComposer=Animation composer ModelFileEditorNodeParticleEmitterInfluencers=Influenceurs ModelFileEditorNodeParticleEmitterInfluencerEmpty=influenceur vide ModelFileEditorNodeParticleEmitterInfluencerDefault=influenceur par défaut diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties index d9328f54..9affb520 100644 --- a/src/main/resources/messages/messages_ru.properties +++ b/src/main/resources/messages/messages_ru.properties @@ -152,6 +152,7 @@ ModelFileEditorNodePointLight=Точечный источник света ModelFileEditorNodeSpotLight=Световое пятно ModelFileEditorNodeLightProbe=Цветопроба ModelFileEditorNodeAnimControl=Анимация +ModelFileEditorNodeAnimComposer=Композитор анимаций ModelFileEditorNodeParticleEmitterInfluencers=Воздействия ModelFileEditorNodeParticleEmitterInfluencerEmpty=Пустое воздействие ModelFileEditorNodeParticleEmitterInfluencerDefault=Стандартное воздействие diff --git a/src/main/resources/messages/messages_zh_CN.properties b/src/main/resources/messages/messages_zh_CN.properties index a764eb61..76b135c8 100644 --- a/src/main/resources/messages/messages_zh_CN.properties +++ b/src/main/resources/messages/messages_zh_CN.properties @@ -153,6 +153,7 @@ ModelFileEditorNodePointLight=\u70B9\u5149\u6E90 ModelFileEditorNodeSpotLight=\u805A\u5149\u706F ModelFileEditorNodeLightProbe=\u706F\u5149\u63A2\u9488 ModelFileEditorNodeAnimControl=\u52A8\u753B +ModelFileEditorNodeAnimComposer=Animation composer ModelFileEditorNodeParticleEmitterInfluencers=\u7C92\u5B50\u53D1\u5C04\u5F71\u54CD\u5668 ModelFileEditorNodeParticleEmitterInfluencerEmpty=\u65E0\u5F71\u54CD\u5668 ModelFileEditorNodeParticleEmitterInfluencerDefault=\u9ED8\u8BA4\u5F71\u54CD\u5668 diff --git a/src/main/resources/ui/css/custom_classes.css b/src/main/resources/ui/css/custom_classes.css index a35daba7..24be431f 100644 --- a/src/main/resources/ui/css/custom_classes.css +++ b/src/main/resources/ui/css/custom_classes.css @@ -595,8 +595,8 @@ ******************************************************************************/ .settings-dialog { - -fx-min-height: 500px; - -fx-min-width: 800px; + -fx-min-height: 400px; + -fx-min-width: 700px; } .settings-dialog-container { @@ -626,20 +626,19 @@ -fx-background-color: -var-background-color; } -.audio-view-editor-container > .label { +.audio-view-editor-container > .hbox > .grid-pane > .label { -fx-alignment: center-right; -fx-min-width: 200px; -fx-pref-width: -fx-min-width; -fx-max-width: -fx-min-width; - -fx-font-size: 16px; -fx-padding: 0px 6px 0px 0px; } -.audio-view-editor-container > .text-field { +.audio-view-editor-container > .hbox > .grid-pane > .text-field { -fx-min-width: 200px; -fx-pref-width: -fx-min-width; -fx-max-width: -fx-min-width; - -fx-font-size: 16px; + -fx-focus-traversable: false; } .audio-view-editor-container > .hbox { diff --git a/src/test/java/com/ss/editor/test/internal/SetUpApplicationTest.java b/src/test/java/com/ss/editor/test/internal/SetUpApplicationTest.java index 6c40c565..d4580588 100644 --- a/src/test/java/com/ss/editor/test/internal/SetUpApplicationTest.java +++ b/src/test/java/com/ss/editor/test/internal/SetUpApplicationTest.java @@ -2,7 +2,6 @@ import com.ss.editor.JfxApplication; import com.ss.editor.config.CommandLineConfig; -import com.ss.editor.manager.InitializationManager; import com.ss.rlib.common.concurrent.util.ThreadUtils; import com.ss.rlib.common.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; @@ -32,8 +31,9 @@ protected static synchronized void waitForApp() { try { final Path asset = Files.createTempDirectory("asset"); - final InitializationManager initializationManager = InitializationManager.getInstance(); - initializationManager.addOnFinishLoading(COUNT_DOWN_LATCH::countDown); + //FIXME + //final InitializationManager initializationManager = InitializationManager.getInstance(); + //initializationManager.addOnFinishLoading(COUNT_DOWN_LATCH::countDown); JfxApplication.main(ArrayFactory.toArray( CommandLineConfig.PREF_EDITOR_ASSET_FOLDER + "=" + asset.toString())); diff --git a/src/test/java/com/ss/editor/test/internal/plugin/RegisterPluginExtensionsTest.java b/src/test/java/com/ss/editor/test/internal/plugin/RegisterPluginExtensionsTest.java index 9f7b7e48..46ff6b8f 100644 --- a/src/test/java/com/ss/editor/test/internal/plugin/RegisterPluginExtensionsTest.java +++ b/src/test/java/com/ss/editor/test/internal/plugin/RegisterPluginExtensionsTest.java @@ -1,8 +1,5 @@ package com.ss.editor.test.internal.plugin; -import com.jme3.post.filters.FXAAFilter; -import com.ss.editor.manager.InitializationManager; -import com.ss.editor.plugin.api.RenderFilterExtension; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; @@ -12,15 +9,16 @@ public class RegisterPluginExtensionsTest { @NotNull - private static final InitializationManager MANAGER = InitializationManager.getInstance(); + //FIXME + //private static final InitializationManager MANAGER = InitializationManager.getInstance(); @Test public void registerFilter() { - MANAGER.addOnAfterCreateJmeContext(() -> { + /* MANAGER.addOnAfterCreateJmeContext(() -> { final FXAAFilter filter = new FXAAFilter(); final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); filterExtension.register(filter); filterExtension.setOnRefresh(filter, Object::notify); - }); + });*/ } }