From 771a2dfa6410d6f38e858ce3ab1c941888ce1c22 Mon Sep 17 00:00:00 2001 From: MJ Date: Tue, 12 Oct 2021 11:49:44 +0200 Subject: [PATCH 01/13] Prepared for the next release. #392 --- CHANGELOG.md | 2 ++ README.md | 2 +- version.txt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6892cea..a9a00bed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob/master/CHANGES)._ +#### 1.10.0-SNAPSHOT + #### 1.10.0-b4 - **[UPDATE]** Updated to Gradle 7.2. diff --git a/README.md b/README.md index 496c628f..d8dba407 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Browse through the directories in the root folder to find out more about each li All functionalities are documented with Kotlin _KDocs_. You can access the source documentation by: - Viewing the generated Dokka files hosted on the [project website](https://libktx.github.io/docs/). -- Extracting the `doc` folders with Dokka files from [release archives](https://github.com/libktx/ktx/releases). +- Extracting the `doc` folders with Dokka files from the [release archives](https://github.com/libktx/ktx/releases). - Reading the sources directly. ### Links diff --git a/version.txt b/version.txt index 5db18665..8c29cb41 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.10.0-b4 +1.10.0-SNAPSHOT From 1c94555b5fcee2f71d4b525f74af1c7978cdfb19 Mon Sep 17 00:00:00 2001 From: MJ Date: Sat, 23 Oct 2021 21:24:30 +0200 Subject: [PATCH 02/13] Kotlin scripting engine. #394 --- .github/CONTRIBUTING.md | 2 + CHANGELOG.md | 12 + README.md | 19 +- .../src/main/kotlin/ktx/graphics/camera.kt | 2 +- script/README.md | 192 +++++++++++++ script/build.gradle.kts | 8 + script/gradle.properties | 2 + .../kotlin/ktx/script/KotlinScriptEngine.kt | 125 +++++++++ .../ktx/script/KotlinScriptEngineTest.kt | 264 ++++++++++++++++++ .../test/resources/ktx/script/broken.script | 1 + .../src/test/resources/ktx/script/script.kts | 1 + settings.gradle.kts | 1 + 12 files changed, 619 insertions(+), 10 deletions(-) create mode 100644 script/README.md create mode 100644 script/build.gradle.kts create mode 100644 script/gradle.properties create mode 100644 script/src/main/kotlin/ktx/script/KotlinScriptEngine.kt create mode 100644 script/src/test/kotlin/ktx/script/KotlinScriptEngineTest.kt create mode 100644 script/src/test/resources/ktx/script/broken.script create mode 100644 script/src/test/resources/ktx/script/script.kts diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c5bdf897..0e343336 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -115,6 +115,8 @@ should generally consist of the following sections: - README.md ``` +- Include the module in the listing in the main [`README.md`](../README.md) file. + ## Maintenance The following sections are for the maintainers of the repository. diff --git a/CHANGELOG.md b/CHANGELOG.md index a9a00bed..d1fbc7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob #### 1.10.0-SNAPSHOT +- **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime. + - `evaluate(String)`: compiles and executes a script passed as a string. + - `evaluate(FileHandle)`: compiles and executes a script from the selected file. + - `evaluateAs(String)`: compiles and executes a script passed as a string. Casts the result to `T`. + - `evaluateAs(FileHandle)`: compiles and executes a script from the selected file. Casts the result to `T`. + - `set(String, Any)`: adds a variable to the script execution context. + - `get(String)`: returns the current value assigned to the selected variable. + - `remove(String)`: removes the variable registered under the given name. + - `import(String, String?)`: adds an import to the script context. Accepts optional alias. + - `importAll(vararg String)`, `importAll(Iterable)`: adds the selected imports to the script context. + - `setPackage(String)`: sets the package for the scripts. + #### 1.10.0-b4 - **[UPDATE]** Updated to Gradle 7.2. diff --git a/README.md b/README.md index d8dba407..62cc27dd 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,15 @@ utilities and extensions for selected parts of libGDX with poor Kotlin support. Examples of Kotlin language features used to improve usability, performance, and readability of libGDX include: -* *Operator overloads* for collections and mathematical operations. -* *Extension methods* improving original libGDX APIs without the use of inheritance. -* *Inline methods* with reduced runtime overhead for various listeners, builders, and loggers. -* *Nullable types* which improve typing information of selected interfaces and functions. -* *Default parameters* reducing boilerplate code. -* *Type-safe builders* for GUI, styling, and physics engine. -* *Default interface methods* for common interfaces, simplifying their implementations. -* *Coroutines context* providing concurrency utilities and non-blocking asset loading. -* *Reified types* that simplify usage of methods normally consuming `Class` parameters. +- *Operator overloads* for collections and mathematical operations. +- *Extension methods* improving original libGDX APIs without the use of inheritance. +- *Inline methods* with reduced runtime overhead for various listeners, builders, and loggers. +- *Nullable types* which improve typing information of selected interfaces and functions. +- *Default parameters* reducing boilerplate code. +- *Type-safe builders* for GUI, styling, and physics engine. +- *Default interface methods* for common interfaces, simplifying their implementations. +- *Coroutines context* providing concurrency utilities and non-blocking asset loading. +- *Reified types* that simplify usage of methods normally consuming `Class` parameters. See the [_Choosing **KTX**_](https://github.com/libktx/ktx/wiki/Choosing-KTX) article for pros and cons of this framework. @@ -53,6 +53,7 @@ Module | Description [`ktx-preferences`](preferences) | Improved API for accessing and saving [preferences](https://github.com/libgdx/libgdx/wiki/Preferences). [`ktx-reflect`](reflect) | Utilities for libGDX [reflection API](https://github.com/libgdx/libgdx/wiki/Reflection). [`ktx-scene2d`](scene2d) | Type-safe Kotlin builders for [`Scene2D`](https://github.com/libgdx/libgdx/wiki/Scene2d) GUI. +[`ktx-script`](script) | Kotlin scripting engine for desktop applications. [`ktx-style`](style) | Type-safe Kotlin builders for `Scene2D` widget styles extending `Skin` API. [`ktx-tiled`](tiled) | Utilities for [Tiled](https://www.mapeditor.org/) maps. [`ktx-vis`](vis) | Type-safe Kotlin builders for [`VisUI`](https://github.com/kotcrab/vis-ui/). diff --git a/graphics/src/main/kotlin/ktx/graphics/camera.kt b/graphics/src/main/kotlin/ktx/graphics/camera.kt index 86e2ae57..16128056 100644 --- a/graphics/src/main/kotlin/ktx/graphics/camera.kt +++ b/graphics/src/main/kotlin/ktx/graphics/camera.kt @@ -145,7 +145,7 @@ class LetterboxingViewport( private companion object { private fun isMobile() = Gdx.app.type == Android || Gdx.app.type == iOS - internal val defaultTargetPpi: Float + private val defaultTargetPpi: Float get() = if (isMobile()) 160f else 96f } } diff --git a/script/README.md b/script/README.md new file mode 100644 index 00000000..66592662 --- /dev/null +++ b/script/README.md @@ -0,0 +1,192 @@ +[![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-script.svg)](https://search.maven.org/artifact/io.github.libktx/ktx-script) + +# KTX: Kotlin script engine + +Kotlin script engine for the desktop platform. + +### Why? + +`ktx-script` can run Kotlin scripts at runtime - either passed as a string, or read from a `FileHandle`. +This can be used as a basis for a custom scripting engine for your application. + +### Guide + +To execute Kotlin scripts, create a `KotlinScriptEngine` instance. This class has the following methods: + +- `evaluate(String)`: compiles and executes a script passed as a string. +Returns the last expression from the script as `Any?`. +- `evaluate(FileHandle)`: compiles and executes a script from the selected file. +Returns the last expression from the script as `Any?`. +- `evaluateAs(String)`: compiles and executes a script passed as a string. +Returns the last expression from the script as `T`. Throws `ClassCastException` if the result does not match `T` type. +- `evaluateAs(FileHandle)`: compiles and executes a script from the selected file. +Returns the last expression from the script as `Any?`. Throws `ClassCastException` if the result does not match `T` type. + +- `set(String, Any)`: adds a variable to the script execution context. +The variable will be available in the scripts under the given name. +- `get(String)`: returns the current value assigned to the selected variable. +- `remove(String)`: removes the variable registered under the given name. +Returns the removed value, or null if no variable was registered. + +- `import(String, String?)`: adds an import to the script context. Wildcard imports are supported. +Takes an optional alias. +- `importAll(vararg String)`, `importAll(Iterable)`: adds the selected imports to the script context. +- `setPackage(String)`: sets the package for the scripts. The scripts will have access to any classes and functions +within the selected package without the need for explicit imports. + +This module depends on the `org.jetbrains.kotlin:kotlin-scripting-jsr223` package. To change the version of the +scripting engine, override this dependency in your Gradle or Maven setup. + +#### Known issues + +* **Limited to the desktop platform.** Other libGDX backends do not support script engines. +* **Slow startup time.** Evaluating initial scripts might take several seconds. +Performance improves with subsequent script evaluations, but it is still not on par with +precompiled Kotlin. +* **Script package can only be chosen once.** As of Kotlin 1.5.31, if multiple scripts define `package`, +or if the package was already set with `KotlinScriptEngine.setPackage`, it cannot be overridden. +* **Lambdas cannot be set as script variables directly.** +Instead, define lambdas or functions in the global scope and import them, or pass objects with lambda variables. +* **Lambdas cannot be returned by the scripts.** Pass objects instead. +Returned objects can have lambda variables. +* **IDE support for scripts might not be complete.** If you specify variables, imports, or package using +the engine instance, IDE might not be able to pick them up without additional setup. +* **Scripts might be unable to infer the generic types.** Avoid passing generic objects as variables to the scripts. + +#### Advantages over using `ScriptEngine` directly + +* Explicit Kotlin types with nullability info. +* `FileHandle` support. +* Imports and package setters. + +Note that this module uses JSR-223 `ScriptEngine` internally. For more customization options, +use the experimental scripting engine from the `org.jetbrains.kotlin:kotlin-scripting-jvm-host` package. + +### Usage examples + +Creating a new script engine: + +```kotlin +import ktx.script.KotlinScriptEngine + +val engine = KotlinScriptEngine() +``` + +Executing a basic script: + +```kotlin +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + engine.evaluate(""" + println("Hello from script!") + """) +} +``` + +Executing a script from a file: + +```kotlin +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.files.FileHandle +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + // You can also use ktx-assets utilities to obtain a file handle. + val file: FileHandle = Gdx.files.internal("script.kts") + engine.evaluate(file) +} +``` + +Using the returned value from a script: + +```kotlin +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + // When you use evaluateAs instead of evaluate, the result + // of the script is automatically cast to the chosen type: + val text = engine.evaluateAs(""" + // The result of the script is its last expression: + "Hello from script!" + """) + println(text) +} +``` + +Adding a variable to the script context: + +```kotlin +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + engine["myVariable"] = "Hello" + engine.evaluate(""" + println(myVariable + " from script!") + """) +} +``` + +Loading a `Texture` from within a script: + +```kotlin +import com.badlogic.gdx.graphics.Texture +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + val texture = engine.evaluateAs(""" + import com.badlogic.gdx.graphics.Texture + + Texture("image.png") + """) +} +``` + +Adding an import to the script scope: + +```kotlin +import com.badlogic.gdx.utils.Array as GdxArray +import ktx.script.KotlinScriptEngine + +fun executeScript(engine: KotlinScriptEngine) { + // You can automatically import any class (or package) for your scripts. + // When importing individual classes or functions, you can assign an + // optional alias: + engine.import("com.badlogic.gdx.utils.Array", alias = "GdxArray") + val texts = engine.evaluateAs>(""" + GdxArray.with("Hello", "from", "script!") + """) + println(texts) +} +``` + +Setting the package of the scripts: + +```kotlin +package ktx.script.example + +import ktx.script.KotlinScriptEngine + +data class Example(val text: String) + +fun executeScript(engine: KotlinScriptEngine) { + engine.setPackage("ktx.script.example") + val example = engine.evaluateAs(""" + // When you set a package for your scripts, + // explicit imports are no longer necessary: + Example(text = "Hello from script!") + """) + println(example) +} +``` + +### Alternatives + +- Using the JSR-223 `ScriptEngine` directly. +- Using the experimental `BasicJvmScriptingHost` from the `org.jetbrains.kotlin:kotlin-scripting-jvm-host` package. +- Using other scripting languages, via JSR-223 API or otherwise. + +#### Additional documentation + +- [The Kotlin scripting proposal](https://github.com/Kotlin/KEEP/blob/master/proposals/scripting-support.md). +- [The `Kotlin/kotlin-script-examples` repository](https://github.com/Kotlin/kotlin-script-examples). diff --git a/script/build.gradle.kts b/script/build.gradle.kts new file mode 100644 index 00000000..439413a8 --- /dev/null +++ b/script/build.gradle.kts @@ -0,0 +1,8 @@ +import ktx.* + +dependencies { + api(kotlin("scripting-jsr223")) + + testImplementation("com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion") + testImplementation("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop") +} diff --git a/script/gradle.properties b/script/gradle.properties new file mode 100644 index 00000000..e5e1f15f --- /dev/null +++ b/script/gradle.properties @@ -0,0 +1,2 @@ +projectName=ktx-script +projectDesc=Kotlin scripting engine for libGDX applications. diff --git a/script/src/main/kotlin/ktx/script/KotlinScriptEngine.kt b/script/src/main/kotlin/ktx/script/KotlinScriptEngine.kt new file mode 100644 index 00000000..1476a2a0 --- /dev/null +++ b/script/src/main/kotlin/ktx/script/KotlinScriptEngine.kt @@ -0,0 +1,125 @@ +package ktx.script + +import com.badlogic.gdx.files.FileHandle +import com.badlogic.gdx.utils.GdxRuntimeException +import java.lang.IllegalStateException +import javax.script.ScriptContext +import javax.script.ScriptEngine +import javax.script.ScriptEngineManager + +/** + * Executes Kotlin scripts in runtime. + * + * Wraps around JSR-223 [ScriptEngine] for the Kotlin language. + */ +class KotlinScriptEngine { + /** Direct reference to the wrapped JSR-223 [ScriptEngine]. */ + val engine: ScriptEngine = ScriptEngineManager().getEngineByExtension("kts") + ?: throw IllegalStateException( + "Unable to find engine for extension: kts. " + + "Make sure to include the org.jetbrains.kotlin:kotlin-scripting-jsr223 dependency." + ) + + /** + * Imports the selected [import] using an optional [alias]. Wildcard imports using `*` are supported, but they + * cannot have an [alias]. + * + * If an [alias] is given, the [import] will be executed with a Kotlin import alias using the `as` operator. + * The [import] will be available in future scripts. + * + * Example usage: `engine.import("com.badlogic.gdx.utils.*")` + * + * When performing multiple imports at once, use [importAll] instead. + */ + fun import(import: String, alias: String? = null) { + val script = if (alias.isNullOrBlank()) "import $import" else "import $import as $alias" + evaluate(script) + } + + /** + * Imports the selected [imports] within the script context. Wildcard imports using `*` are accepted. + * The [imports] will be available in future scripts. + * + * To assign an alias to a specific import, use Kotlin `as` operator after the qualified name. + * For example: `engine.importAll("com.badlogic.gdx.utils.Array as GdxArray") + */ + fun importAll(vararg imports: String) { + val script = imports.joinToString(separator = "\n") { "import $it" } + evaluate(script) + } + + /** + * Imports the selected [imports] within the script context. Wildcard imports using `*` are accepted. + * The [imports] will be available in future scripts. + * + * To assign an alias to a specific import, use Kotlin `as` operator after the qualified name. + * For example: `engine.importAll("com.badlogic.gdx.utils.Array as GdxArray") + */ + fun importAll(imports: Iterable) { + val script = imports.joinToString(separator = "\n") { "import $it" } + evaluate(script) + } + + /** + * Sets the package of the future scripts to [name]. + * + * Note that the Kotlin script engine implementation might prohibit from changing the package. + * As a result, subsequent calls of this method might have no effect. + * To execute scripts from within multiple packages, create multiple script engines. + */ + fun setPackage(name: String) { + evaluate("package $name") + } + + /** + * Retrieves the value assigned to [variable] in the context of this [engine]. + */ + inline operator fun get(variable: String): T? = + engine.get(variable) as? T + + /** + * Assigns the selected [value] to the [variable] name in the context of this [engine]. + * The [variable] will be available in the future scripts. + */ + operator fun set(variable: String, value: T) = + engine.put(variable, value) + + /** + * Removes the [variable] from the context of this [engine]. Returns the value assigned to the [variable]. + * Returns null if no value is assigned to [variable]. + */ + fun remove(variable: String): Any? = + engine.context.removeAttribute(variable, ScriptContext.ENGINE_SCOPE) + + /** + * Executes the selected [script]. Returns the last script's expression as the result. + * If unable to execute the script, [GdxRuntimeException] will be thrown. + */ + fun evaluate(script: String): Any? = try { + engine.eval(script) + } catch (exception: Throwable) { + throw GdxRuntimeException("Unable to execute Kotlin script:\n$script", exception) + } + + /** + * Executes the selected [scriptFile]. Returns the last script's expression as the result. + * If unable to execute the script, [GdxRuntimeException] will be thrown. + */ + fun evaluate(scriptFile: FileHandle): Any? = try { + engine.eval(scriptFile.reader()) + } catch (exception: Throwable) { + throw GdxRuntimeException("Unable to execute Kotlin script from file: $scriptFile", exception) + } + + /** + * Executes the selected [script] and returns an instance of [T]. If the script is not an instance of [T], + * [ClassCastException] will be thrown. If unable to execute the script, [GdxRuntimeException] will be thrown. + */ + inline fun evaluateAs(script: String): T = evaluate(script) as T + + /** + * Executes the selected [scriptFile] and returns an instance of [T]. If the script is not an instance of [T], + * [ClassCastException] will be thrown. If unable to execute the script, [GdxRuntimeException] will be thrown. + */ + inline fun evaluateAs(scriptFile: FileHandle): T = evaluate(scriptFile) as T +} diff --git a/script/src/test/kotlin/ktx/script/KotlinScriptEngineTest.kt b/script/src/test/kotlin/ktx/script/KotlinScriptEngineTest.kt new file mode 100644 index 00000000..d4d17609 --- /dev/null +++ b/script/src/test/kotlin/ktx/script/KotlinScriptEngineTest.kt @@ -0,0 +1,264 @@ +package ktx.script + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Files +import com.badlogic.gdx.utils.GdxRuntimeException +import io.kotlintest.matchers.shouldThrow +import org.junit.AfterClass +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertSame +import org.junit.BeforeClass +import org.junit.Test +import java.lang.ClassCastException +import kotlin.reflect.KClass +import com.badlogic.gdx.utils.Array as GdxArray + +/** + * Tests the [KotlinScriptEngine]. + */ +class KotlinScriptEngineTest { + data class Data(var text: String) + private val engine = KotlinScriptEngine() + + companion object { + @JvmStatic + @BeforeClass + fun `initiate libGDX files`() { + Gdx.files = Lwjgl3Files() + } + + @JvmStatic + @AfterClass + fun `remove libGDX files`() { + Gdx.files = null + } + } + + @Test + fun `should create Kotlin scripting engine`() { + // When: + val scriptEngine = engine.engine + + // Then: + assertEquals("kotlin", scriptEngine.factory.languageName) + } + + @Test + fun `should import class`() { + // When: + engine.import("ktx.script.KotlinScriptEngineTest.Data") + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Data("test")""")) + } + + @Test + fun `should import class with alias`() { + // When: + engine.import("ktx.script.KotlinScriptEngineTest.Data", alias = "Alias") + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Alias("test")""")) + } + + @Test + fun `should import classes`() { + // When: + engine.importAll("ktx.script.KotlinScriptEngineTest.Data") + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Data("test")""")) + } + + @Test + fun `should import classes with aliases`() { + // When: + engine.importAll("ktx.script.KotlinScriptEngineTest.Data as Alias") + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Alias("test")""")) + } + @Test + fun `should import classes from iterable`() { + // When: + engine.importAll(listOf("ktx.script.KotlinScriptEngineTest.Data")) + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Data("test")""")) + } + + @Test + fun `should import classes with aliases from iterable`() { + // When: + engine.importAll(listOf("ktx.script.KotlinScriptEngineTest.Data as Alias")) + + // Then: + assertEquals(Data("test"), engine.evaluateAs("""Alias("test")""")) + } + + @Test + fun `should set script package`() { + // When: + engine.setPackage("ktx.script") + + // Then: should access classes without an import: + assertEquals(KotlinScriptEngineTest::class, engine.evaluateAs>("KotlinScriptEngineTest::class")) + } + + @Test + fun `should evaluate script`() { + // When: + val result = engine.evaluate("42") + + // Then: + assertEquals(42, result) + } + + @Test + fun `should throw exception if unable to evaluate script`() { + // Expect: + shouldThrow { + engine.evaluate("import") + } + } + + @Test + fun `should evaluate script from file`() { + // Given: + val file = Gdx.files.classpath("ktx/script/script.kts") + + // When: + val result = engine.evaluate(file) + + // Then: + assertEquals("test", result) + } + + @Test + fun `should throw exception if unable to evaluate script from file`() { + // Given: + val file = Gdx.files.classpath("ktx/script/broken.script") + + // Expect: + shouldThrow { + engine.evaluate(file) + } + } + + @Test + fun `should evaluate script and return its result`() { + // When: + val result = engine.evaluateAs("42") + + // Then: + assertEquals(42, result) + } + + @Test + fun `should throw exception if the script result does not match the expected type`() { + // Expect: + shouldThrow { + engine.evaluateAs("1") + } + } + + @Test + fun `should evaluate script from file and return its result`() { + // Given: + val file = Gdx.files.classpath("ktx/script/script.kts") + + // When: + val result = engine.evaluateAs(file) + + // Then: + assertEquals("test", result) + } + + @Test + fun `should throw exception if the result of script from file does not match the expected type`() { + // Given: + val file = Gdx.files.classpath("ktx/script/script.kts") + + // Expect: + shouldThrow { + engine.evaluateAs(file) + } + } + + @Test + fun `should execute script with custom functions, lambdas and classes`() { + // Given: + engine.setPackage("ktx.script") + engine.import("com.badlogic.gdx.utils.Array", alias = "GdxArray") + + // When: + val result = engine.evaluate( + """ + class Helper { + fun toArray(vararg objects: Any) = GdxArray.with(*objects) + } + fun data(text: String) = KotlinScriptEngineTest.Data(text) + val lambda: () -> String = { "test" } + + Helper().toArray(data(lambda()), data(lambda()), data(lambda())) + """.trimIndent() + ) + + // Then: + assertEquals(GdxArray.with(Data("test"), Data("test"), Data("test")), result) + } + + @Test + fun `should assign context variable`() { + // Given: + val variable = Data("test") + + // When: + engine["variable"] = variable + + // Then: + assertSame(variable, engine["variable"]) + assertEquals("test", engine.evaluateAs("variable.text")) + } + + @Test + fun `should allow to modify context variable`() { + // Given: + val variable = Data("test") + engine["variable"] = variable + + // When: + engine.evaluate( + """ + variable.text = "new" + """.trimIndent() + ) + + // Then: + assertEquals("new", variable.text) + } + + @Test + fun `should remove context variable`() { + // Given: + val variable = Data("test") + engine["variable"] = variable + + // When: + val removed = engine.remove("variable") + + // Then: + assertNull(engine["variable"]) + assertSame(variable, removed) + } + + @Test + fun `should not throw an exception when removing an absent variable`() { + // When: + val result = engine.remove("absent") + + // Then: + assertNull(result) + } +} diff --git a/script/src/test/resources/ktx/script/broken.script b/script/src/test/resources/ktx/script/broken.script new file mode 100644 index 00000000..621a1cb2 --- /dev/null +++ b/script/src/test/resources/ktx/script/broken.script @@ -0,0 +1 @@ +import diff --git a/script/src/test/resources/ktx/script/script.kts b/script/src/test/resources/ktx/script/script.kts new file mode 100644 index 00000000..8b8441b9 --- /dev/null +++ b/script/src/test/resources/ktx/script/script.kts @@ -0,0 +1 @@ +"test" diff --git a/settings.gradle.kts b/settings.gradle.kts index db8bce46..dbb935b8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,6 +25,7 @@ include( "preferences", "reflect", "scene2d", + "script", "style", "tiled", "vis", From 2309f28763a7b2ef6f9d55fba1247111c60c4526 Mon Sep 17 00:00:00 2001 From: MJ Date: Wed, 27 Oct 2021 14:30:22 +0200 Subject: [PATCH 03/13] Kotlin scripting documentation. #394 --- script/README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/script/README.md b/script/README.md index 66592662..fc708bcd 100644 --- a/script/README.md +++ b/script/README.md @@ -20,7 +20,7 @@ Returns the last expression from the script as `Any?`. - `evaluateAs(String)`: compiles and executes a script passed as a string. Returns the last expression from the script as `T`. Throws `ClassCastException` if the result does not match `T` type. - `evaluateAs(FileHandle)`: compiles and executes a script from the selected file. -Returns the last expression from the script as `Any?`. Throws `ClassCastException` if the result does not match `T` type. +Returns the last expression from the script as `T`. Throws `ClassCastException` if the result does not match `T` type. - `set(String, Any)`: adds a variable to the script execution context. The variable will be available in the scripts under the given name. @@ -44,20 +44,25 @@ scripting engine, override this dependency in your Gradle or Maven setup. Performance improves with subsequent script evaluations, but it is still not on par with precompiled Kotlin. * **Script package can only be chosen once.** As of Kotlin 1.5.31, if multiple scripts define `package`, -or if the package was already set with `KotlinScriptEngine.setPackage`, it cannot be overridden. +or if the package was already set with `KotlinScriptEngine.setPackage`, it cannot be overridden. Once the package +is set, all scripts will be executed from the same package, even if they attempt to override it. * **Lambdas cannot be set as script variables directly.** Instead, define lambdas or functions in the global scope and import them, or pass objects with lambda variables. -* **Lambdas cannot be returned by the scripts.** Pass objects instead. -Returned objects can have lambda variables. +* **Lambdas cannot be returned by the scripts directly.** Pass objects instead. +Note that returned objects can have lambda variables. +* **Defined variables stay in the script scope.** While you can declare a top-level `val` or `var` that will be +available for all future scripts, their values cannot be retrieved with `KotlinScriptEngine.get`. Instead, they +have to be returned as script results, or otherwise passed outside the script context. * **IDE support for scripts might not be complete.** If you specify variables, imports, or package using the engine instance, IDE might not be able to pick them up without additional setup. * **Scripts might be unable to infer the generic types.** Avoid passing generic objects as variables to the scripts. +* **Targets Java 8.** Using newer language features might result in exceptions. #### Advantages over using `ScriptEngine` directly * Explicit Kotlin types with nullability info. * `FileHandle` support. -* Imports and package setters. +* Import and package setters. Note that this module uses JSR-223 `ScriptEngine` internally. For more customization options, use the experimental scripting engine from the `org.jetbrains.kotlin:kotlin-scripting-jvm-host` package. From 96f1376153cc9f0daa53064c2623795668aaf8d9 Mon Sep 17 00:00:00 2001 From: MJ Date: Tue, 16 Nov 2021 09:38:18 +0100 Subject: [PATCH 04/13] Kotlin updated to 1.6.0. #395 --- CHANGELOG.md | 1 + README.md | 2 +- async/src/main/kotlin/ktx/async/async.kt | 2 ++ gradle.properties | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fbc7c1..0a469631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob #### 1.10.0-SNAPSHOT +- **[UPDATE]** Updated to Kotlin 1.6.0. - **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime. - `evaluate(String)`: compiles and executes a script passed as a string. - `evaluate(FileHandle)`: compiles and executes a script from the selected file. diff --git a/README.md b/README.md index 62cc27dd..b6b8e358 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![GitHub Build](https://github.com/libktx/ktx/workflows/build/badge.svg)](https://github.com/libktx/ktx/actions?query=workflow%3Abuild) -[![Kotlin](https://img.shields.io/badge/kotlin-1.5.31-orange.svg)](http://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.6.0-orange.svg)](http://kotlinlang.org/) [![libGDX](https://img.shields.io/badge/libgdx-1.10.0-red.svg)](https://libgdx.com/) [![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-async.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.github.libktx%22) diff --git a/async/src/main/kotlin/ktx/async/async.kt b/async/src/main/kotlin/ktx/async/async.kt index 62d8e7c0..dbdf43c0 100644 --- a/async/src/main/kotlin/ktx/async/async.kt +++ b/async/src/main/kotlin/ktx/async/async.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.utils.async.AsyncExecutor import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext @@ -81,6 +82,7 @@ fun CoroutineScope.isOnRenderingThread() = * frame before resuming, but it will always suspend the current coroutine until the [Runnable] instances scheduled * with [Application.postRunnable] are executed by the [Application]. */ +@OptIn(ExperimentalCoroutinesApi::class) suspend fun skipFrame() { suspendCancellableCoroutine { continuation -> Gdx.app.postRunnable { diff --git a/gradle.properties b/gradle.properties index ae2a5309..0f12c2e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ libGroup=io.github.libktx -kotlinVersion=1.5.31 +kotlinVersion=1.6.0 dokkaVersion=1.5.30 junitPlatformVersion=1.2.0 From 4dfa05bfecb4fb0325fa8cb3197bf8d9340bed88 Mon Sep 17 00:00:00 2001 From: MJ Date: Mon, 22 Nov 2021 20:11:08 +0100 Subject: [PATCH 05/13] Kover plugin. #395 --- build.gradle.kts | 1 + reflect/src/test/kotlin/ktx/reflect/reflectTest.kt | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9819fee1..35f887d0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ plugins { java distribution id("io.codearte.nexus-staging") version "0.22.0" + id("org.jetbrains.kotlinx.kover") version "0.4.2" } repositories { diff --git a/reflect/src/test/kotlin/ktx/reflect/reflectTest.kt b/reflect/src/test/kotlin/ktx/reflect/reflectTest.kt index fe66ed0e..ab65b65b 100644 --- a/reflect/src/test/kotlin/ktx/reflect/reflectTest.kt +++ b/reflect/src/test/kotlin/ktx/reflect/reflectTest.kt @@ -20,6 +20,7 @@ data class Extension(val a: String, val b: String) : Tested() { @Suppress("unused") fun test(c: String): String = a + b + c } +@Suppress("unused") class Container(@JvmField val field: String) enum class Enum { RED, BLUE } @@ -404,8 +405,10 @@ class ReflectTest { // When: val fields = reflectedClass.fields - // Then: - assertEquals(0, fields.size) + // Then: should not find private backing fields: + val fieldNames = fields.map { it.name }.toSet() + assertFalse("a" in fieldNames) + assertFalse("b" in fieldNames) } @Test @@ -417,7 +420,9 @@ class ReflectTest { val fields = reflectedClass.declaredFields // Then: should return custom fields plus internal field. - assertEquals(2 + 1, fields.size) + val fieldNames = fields.map { it.name }.toSet() + assertTrue("a" in fieldNames) + assertTrue("b" in fieldNames) } @Test From 15341a5bd32fe7bc3e43c69fbff26ca5de1366e0 Mon Sep 17 00:00:00 2001 From: MJ Date: Thu, 25 Nov 2021 22:44:51 +0100 Subject: [PATCH 06/13] Kover plugin removal due to CI incompatibility. #395 --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 35f887d0..9819fee1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,6 @@ plugins { java distribution id("io.codearte.nexus-staging") version "0.22.0" - id("org.jetbrains.kotlinx.kover") version "0.4.2" } repositories { From 990a245032770a38128f79a455f26b5cbf21e032 Mon Sep 17 00:00:00 2001 From: Harri Pellikka Date: Sat, 4 Dec 2021 20:00:56 +0200 Subject: [PATCH 07/13] Tree.onItemClick support, #398 - Added support for onItemClick listeners for Trees --- CHANGELOG.md | 1 + actors/README.md | 1 + actors/src/main/kotlin/ktx/actors/events.kt | 15 +++++++++++++++ actors/src/test/kotlin/ktx/actors/EventsTest.kt | 15 +++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a469631..03ba2411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob - `import(String, String?)`: adds an import to the script context. Accepts optional alias. - `importAll(vararg String)`, `importAll(Iterable)`: adds the selected imports to the script context. - `setPackage(String)`: sets the package for the scripts. + - `onItemClick(Node)`: adds a listener that gets invoked when `Node` in a `Tree` gets clicked. #### 1.10.0-b4 diff --git a/actors/README.md b/actors/README.md index 1d045154..b076e7dc 100644 --- a/actors/README.md +++ b/actors/README.md @@ -42,6 +42,7 @@ and `onKeyboardFocusEvent` `Actor` extension methods were added. They consume th parameters. Both listener factory variants are inlined, but the ones ending with *Event* provide more lambda parameters and allow to inspect the original `Event` instance that triggered the listener. Regular listener factory methods should be enough for most use cases. +- Lambda-compatible `Tree.onItemClick` method was added. Allows listening to `Node`s being clicked in `Tree` structures. #### Actions diff --git a/actors/src/main/kotlin/ktx/actors/events.kt b/actors/src/main/kotlin/ktx/actors/events.kt index e311b169..e035fcf3 100644 --- a/actors/src/main/kotlin/ktx/actors/events.kt +++ b/actors/src/main/kotlin/ktx/actors/events.kt @@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.keyDown import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.keyTyped import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.keyUp import com.badlogic.gdx.scenes.scene2d.InputListener +import com.badlogic.gdx.scenes.scene2d.ui.Tree import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent import com.badlogic.gdx.scenes.scene2d.utils.ClickListener @@ -88,6 +89,20 @@ inline fun T.onClickEvent( return clickListener } +/** + * Attaches a [ClickListener] to this tree. + * @param lsitener invoked each time a node in this tree is clicked. Consumes the triggered [InputEvent] and the + * [Tree] the listener was originally attached to as `this`. The received Node is the node that was clicked. + * @return [ClickListener] instance. + */ +inline fun > T.onItemClick(crossinline listener: ((Tree.Node<*, *, *>) -> Unit)): ClickListener { + val clickListener = object : ClickListener() { + override fun clicked(event: InputEvent?, x: Float, y: Float) = listener(selectedNode) + } + addListener(clickListener) + return clickListener +} + /** * Attaches an [InputListener] to this actor. * @param listener invoked each time this actor is touched. Consumes the [Actor] as `this`. diff --git a/actors/src/test/kotlin/ktx/actors/EventsTest.kt b/actors/src/test/kotlin/ktx/actors/EventsTest.kt index c9495c25..5f5ce899 100644 --- a/actors/src/test/kotlin/ktx/actors/EventsTest.kt +++ b/actors/src/test/kotlin/ktx/actors/EventsTest.kt @@ -8,10 +8,12 @@ import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.keyTyped import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.keyUp import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.touchDown import com.badlogic.gdx.scenes.scene2d.InputEvent.Type.touchUp +import com.badlogic.gdx.scenes.scene2d.ui.Tree import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent.Type.keyboard import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent.Type.scroll +import io.kotlintest.mock.mock import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -79,6 +81,19 @@ class EventsTest { assertTrue(listener in actor.listeners) } + @Test + fun `should attach ClickListener to a Tree consuming InputEvent with clicked Node`() { + val style = mock() + style.plus = mock() + style.minus = mock() + val tree = Tree, Any>(style) + + val listener = tree.onItemClick { } + + assertNotNull(listener) + assertTrue(listener in tree.listeners) + } + @Test fun `should attach InputListener for touchDown`() { val actor = Actor() From 5405ad3c4ed98eb694f9c6b164d100b1f4e1566f Mon Sep 17 00:00:00 2001 From: MJ Date: Sat, 18 Dec 2021 13:19:12 +0100 Subject: [PATCH 08/13] Documentation typo fix. #401 --- math/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/math/README.md b/math/README.md index fb627f52..75fe0dd5 100644 --- a/math/README.md +++ b/math/README.md @@ -44,8 +44,8 @@ call `vec in rect` (or `vec !in rect`) to check if the rectangle contains (or do #### `ImmutableVector2` - `ImmutableVector2` is an immutable equivalent to `Vector2`. It provides most of the functionality of `Vector2`, but -mutation methods return new vectors instead of mutate the reference. -- Note that one may want to create type aliases to make the usage more concise: `typealias Vect2 = ImmutableVector2` +mutation methods return new vectors instead of mutating the objects. +- Note that one may want to create type aliases to make the usage more concise: `typealias Vect2 = ImmutableVector2`. - `ImmutableVector` is comparable (`>`, `>=`, `<`, `<=` are available). Comparison is evaluated by length. - Instances can be destructed: `val (x, y) = vector2`. - `Vector2.toImmutable()` Returns an immutable vector with same `x` and `y` attributes than this `Vector2` From 0dc46e489f20f52a44ba1212f06a8792844204a7 Mon Sep 17 00:00:00 2001 From: MJ Date: Wed, 22 Dec 2021 15:14:08 +0100 Subject: [PATCH 09/13] Kotlin 1.6.10 and Coroutines 1.6.0 updates. #395 --- CHANGELOG.md | 3 ++- README.md | 2 +- async/README.md | 2 +- buildSrc/src/main/kotlin/ktx/Versions.kt | 2 +- gradle.properties | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a469631..84bed8c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob #### 1.10.0-SNAPSHOT -- **[UPDATE]** Updated to Kotlin 1.6.0. +- **[UPDATE]** Updated to Kotlin 1.6.10. +- **[UPDATE]** Updated to Kotlin Coroutines 1.6.0. - **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime. - `evaluate(String)`: compiles and executes a script passed as a string. - `evaluate(FileHandle)`: compiles and executes a script from the selected file. diff --git a/README.md b/README.md index b6b8e358..a9506e8c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![GitHub Build](https://github.com/libktx/ktx/workflows/build/badge.svg)](https://github.com/libktx/ktx/actions?query=workflow%3Abuild) -[![Kotlin](https://img.shields.io/badge/kotlin-1.6.0-orange.svg)](http://kotlinlang.org/) +[![Kotlin](https://img.shields.io/badge/kotlin-1.6.10-orange.svg)](http://kotlinlang.org/) [![libGDX](https://img.shields.io/badge/libgdx-1.10.0-red.svg)](https://libgdx.com/) [![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-async.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.github.libktx%22) diff --git a/async/README.md b/async/README.md index 0393cd5b..75c58112 100644 --- a/async/README.md +++ b/async/README.md @@ -1,4 +1,4 @@ -[![Kotlin Coroutines](https://img.shields.io/badge/kotlin--coroutines-1.5.2-orange.svg)](http://kotlinlang.org/) +[![Kotlin Coroutines](https://img.shields.io/badge/kotlin--coroutines-1.6.0-orange.svg)](http://kotlinlang.org/) [![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-async.svg)](https://search.maven.org/artifact/io.github.libktx/ktx-async) # KTX: Coroutines support and parallelization utilities diff --git a/buildSrc/src/main/kotlin/ktx/Versions.kt b/buildSrc/src/main/kotlin/ktx/Versions.kt index e0cb4c90..a237c453 100644 --- a/buildSrc/src/main/kotlin/ktx/Versions.kt +++ b/buildSrc/src/main/kotlin/ktx/Versions.kt @@ -1,7 +1,7 @@ package ktx const val gdxVersion = "1.10.0" -const val kotlinCoroutinesVersion = "1.5.2" +const val kotlinCoroutinesVersion = "1.6.0" const val ashleyVersion = "1.7.4" const val visUiVersion = "1.5.0" diff --git a/gradle.properties b/gradle.properties index 0f12c2e6..b19a63ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ libGroup=io.github.libktx -kotlinVersion=1.6.0 +kotlinVersion=1.6.10 dokkaVersion=1.5.30 junitPlatformVersion=1.2.0 From e600f989bbbfe894a8778db93c4074a4968750a1 Mon Sep 17 00:00:00 2001 From: damios Date: Tue, 18 Jan 2022 20:33:55 +0100 Subject: [PATCH 10/13] Update libGDX wiki links in README files. #402 Merged #403. * Update libGDX wiki links in README * Fix links in nested READMEs Co-authored-by: MJ --- README.md | 14 +++---- actors/README.md | 2 +- app/README.md | 10 ++--- assets-async/README.md | 6 +-- assets/README.md | 12 +++--- async/README.md | 4 +- box2d/README.md | 2 +- collections/README.md | 10 ++--- freetype-async/README.md | 6 +-- freetype/README.md | 8 ++-- graphics/README.md | 16 ++++---- i18n/README.md | 4 +- inject/README.md | 6 +-- json/README.md | 8 ++-- log/README.md | 2 +- math/README.md | 18 ++++----- preferences/README.md | 14 +++---- reflect/README.md | 2 +- .../src/main/kotlin/ktx/reflect/reflect.kt | 2 +- scene2d/README.md | 38 +++++++++---------- style/README.md | 12 +++--- tiled/README.md | 8 ++-- vis-style/README.md | 2 +- vis/README.md | 12 +++--- 24 files changed, 109 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index a9506e8c..b92c66bd 100644 --- a/README.md +++ b/README.md @@ -34,25 +34,25 @@ You can include selected **KTX** modules based on the needs of your application. Module | Description :---: | --- -[`ktx-actors`](actors) | [`Scene2D`](https://github.com/libgdx/libgdx/wiki/Scene2d) GUI extensions for stages, actors, actions, and event listeners. +[`ktx-actors`](actors) | [`Scene2D`](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d) GUI extensions for stages, actors, actions, and event listeners. [`ktx-app`](app) | `ApplicationListener` implementations and general application utilities. [`ktx-ashley`](ashley) | [`Ashley`](https://github.com/libgdx/ashley) entity-component-system utilities. [`ktx-assets`](assets) | Resources management utilities. [`ktx-assets-async`](assets-async) | Non-blocking asset loading using coroutines. [`ktx-async`](async) | [Coroutines](https://kotlinlang.org/docs/reference/coroutines.html) context based on libGDX threading model. -[`ktx-box2d`](box2d) | [`Box2D`](https://github.com/libgdx/libgdx/wiki/Box2d) physics engine utilities. +[`ktx-box2d`](box2d) | [`Box2D`](https://libgdx.com/wiki/extensions/physics/box2d) physics engine utilities. [`ktx-collections`](collections) | Extensions for libGDX custom collections. [`ktx-freetype`](freetype) | `FreeType` fonts loading utilities. [`ktx-freetype-async`](freetype-async) | Non-blocking `FreeType` fonts loading using coroutines. [`ktx-graphics`](graphics) | Utilities related to rendering tools and graphics. [`ktx-i18n`](i18n) | Internationalization API utilities. [`ktx-inject`](inject) | A dependency injection system with low overhead and no reflection usage. -[`ktx-json`](json) | Utilities for libGDX [JSON](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON) serialization API. +[`ktx-json`](json) | Utilities for libGDX [JSON](https://libgdx.com/wiki/utils/reading-and-writing-json) serialization API. [`ktx-log`](log) | Minimal runtime overhead cross-platform logging using inlined functions. [`ktx-math`](math) | Operator functions for libGDX math API and general math utilities. -[`ktx-preferences`](preferences) | Improved API for accessing and saving [preferences](https://github.com/libgdx/libgdx/wiki/Preferences). -[`ktx-reflect`](reflect) | Utilities for libGDX [reflection API](https://github.com/libgdx/libgdx/wiki/Reflection). -[`ktx-scene2d`](scene2d) | Type-safe Kotlin builders for [`Scene2D`](https://github.com/libgdx/libgdx/wiki/Scene2d) GUI. +[`ktx-preferences`](preferences) | Improved API for accessing and saving [preferences](https://libgdx.com/wiki/preferences). +[`ktx-reflect`](reflect) | Utilities for libGDX [reflection API](https://libgdx.com/wiki/utils/reflection). +[`ktx-scene2d`](scene2d) | Type-safe Kotlin builders for [`Scene2D`](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d) GUI. [`ktx-script`](script) | Kotlin scripting engine for desktop applications. [`ktx-style`](style) | Type-safe Kotlin builders for `Scene2D` widget styles extending `Skin` API. [`ktx-tiled`](tiled) | Utilities for [Tiled](https://www.mapeditor.org/) maps. @@ -187,7 +187,7 @@ All functionalities are documented with Kotlin _KDocs_. You can access the sourc Most official guides and code examples in this repository assume that the reader is at least a bit familiar with the libGDX API. If you are just getting to know the framework, it might be helpful to go through -[the official libGDX wiki](https://github.com/libgdx/libgdx/wiki), and convert some Java examples to Kotlin. +[the official libGDX wiki](https://libgdx.com/wiki/), and convert some Java examples to Kotlin. ## [Contribution](.github/CONTRIBUTING.md) diff --git a/actors/README.md b/actors/README.md index 1d045154..6d1c2615 100644 --- a/actors/README.md +++ b/actors/README.md @@ -312,4 +312,4 @@ HTML-inspired syntax. #### Additional documentation -- [Scene2D UI article.](https://github.com/libgdx/libgdx/wiki/Scene2d.ui) +- [Scene2D UI article.](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d-ui) diff --git a/app/README.md b/app/README.md index fa7b0067..ea5b4ff6 100644 --- a/app/README.md +++ b/app/README.md @@ -80,7 +80,7 @@ class MyApplicationListener : KtxApplicationAdapter { } ``` -Implementing `KtxGame` with one screen that displays text with `Batch` utilities from `ktx-graphics`: +Implementing `KtxGame` with one screen that displays text with `Batch` utilities from `ktx-graphics`: ```kotlin import com.badlogic.gdx.Screen @@ -170,7 +170,7 @@ Executing platform-specific code: import ktx.app.Platform fun runOnPlatform() { - Platform.runOnMobile { + Platform.runOnMobile { println("Will print only on mobile platforms!") } } @@ -261,6 +261,6 @@ initiates and handles annotated view instances. #### Additional documentation -- [Official life cycle article.](https://github.com/libgdx/libgdx/wiki/The-life-cycle) -- [Official viewports article.](https://github.com/libgdx/libgdx/wiki/Viewports) -- [Official article on profiling.](https://github.com/libgdx/libgdx/wiki/Profiling) +- [Official life cycle article.](https://libgdx.com/wiki/app/the-life-cycle) +- [Official viewports article.](https://libgdx.com/wiki/graphics/viewports) +- [Official article on profiling.](https://libgdx.com/wiki/graphics/profiling) diff --git a/assets-async/README.md b/assets-async/README.md index 7a6030f3..6772d02c 100644 --- a/assets-async/README.md +++ b/assets-async/README.md @@ -966,7 +966,7 @@ and fully compatible with coroutines. It offers superior performance and better should be used instead only as an intermediate step during migration from an `AssetManager` to the `AssetStorage`, or if an `AssetManager` is strictly required by an otherwise incompatible third-party API. -`AsyncAssetManager` supports all features of the [`AssetManager`](https://github.com/libgdx/libgdx/wiki/Managing-your-assets). +`AsyncAssetManager` supports all features of the [`AssetManager`](https://libgdx.com/wiki/managing-your-assets). The main difference is that `loadAsync` should be used over the standard `load` methods whenever you need a reference to the loaded asset or need full control over its error handling. @@ -1130,7 +1130,7 @@ There seem to be no other coroutines-based asset loaders available. However, libGDX `AssetManager` is still viable when efficient parallel loading is not a requirement. Alternatives to the `AssetStorage` and `AsyncAssetManager` include: -- Using [`AssetManager`](https://github.com/libgdx/libgdx/wiki/Managing-your-assets) directly. +- Using [`AssetManager`](https://libgdx.com/wiki/managing-your-assets) directly. - Using [`ktx-assets`](../assets) extensions for `AssetManager`. - [`AnnotationAssetManager`](https://bitbucket.org/dermetfan/libgdx-utils/wiki/net.dermetfan.gdx.assets.AnnotationAssetManager) from [`libgdx-utils`](https://bitbucket.org/dermetfan/libgdx-utils) that extends `AssetManager` and allows @@ -1140,4 +1140,4 @@ specifying assets for loading by marking fields with annotations. #### Additional documentation - [`ktx-async` module](../async), which is used extensively by this extension. -- [Official libGDX `AssetManager` article.](https://github.com/libgdx/libgdx/wiki/Managing-your-assets) +- [Official libGDX `AssetManager` article.](https://libgdx.com/wiki/managing-your-assets) diff --git a/assets/README.md b/assets/README.md index 15068881..199a372b 100644 --- a/assets/README.md +++ b/assets/README.md @@ -64,9 +64,9 @@ loaded in the first place. Typical usage: `assetManager.unloadSafely("test.png") exception thrown during reloading. Note that `AssetManager` can throw `GdxRuntimeException` if the asset was not loaded yet. - `AssetManager.getLoader` and `setLoader` extension methods with reified types added to ease handling of `AssetLoader` instances registered in the `AssetManager`. -- The `AssetGroup` class is provided for easily grouping together assets so they can be managed as a group through calls +- The `AssetGroup` class is provided for easily grouping together assets so they can be managed as a group through calls such as `loadAll()` or `unloadAll()`. The intended use is to subclass `AssetGroup` and list its member assets as -properties using `AssetGroup.asset()` or `AssetGroup.delayedAsset()`. It also allows for using a common prefix for +properties using `AssetGroup.asset()` or `AssetGroup.delayedAsset()`. It also allows for using a common prefix for the file names of the group in case they are stored in a specific subdirectory. #### `Disposable` @@ -86,7 +86,7 @@ needed. See `Throwable.ignore()` documentation for further details. `DisposableContainer` is a `Disposable` implementation that stores a set of `Disposable` instances to be disposed all at once. -When subclassed or used as a delegate via its `DisposableRegistry` interface, it provides an `alsoRegister` extension, +When subclassed or used as a delegate via its `DisposableRegistry` interface, it provides an `alsoRegister` extension, which allows to easily add items to the container so that they will be automatically disposed when the containing class is. #### `Pool` @@ -355,7 +355,7 @@ val uiAssets = UIAssets(manager) // No need to queue the assets. They are queued when creating the group object. // Block until they are finished loading: -uiAssets.finishLoading() +uiAssets.finishLoading() // Note that classic incremental loading with update() is also available. // Accessing assets - same as with regular properties: @@ -455,5 +455,5 @@ Java applications though - **KTX** syntax should feel more natural when using Ko #### Additional documentation -- [`AssetManager` article.](https://github.com/libgdx/libgdx/wiki/Managing-your-assets) -- [`FileHandle` article.](https://github.com/libgdx/libgdx/wiki/File-handling) +- [`AssetManager` article.](https://libgdx.com/wiki/managing-your-assets) +- [`FileHandle` article.](https://libgdx.com/wiki/file-handling) diff --git a/async/README.md b/async/README.md index 75c58112..511ccd41 100644 --- a/async/README.md +++ b/async/README.md @@ -339,7 +339,7 @@ import ktx.async.httpRequest import ktx.async.RenderingScope class MyScreen: Screen, CoroutineScope by RenderingScope() { - // Implement your application screen here. + // Implement your application screen here. override fun hide() { // Cancels any running coroutines when leaving the screen: @@ -395,6 +395,6 @@ of compatibility with existing libGDX APIs though. #### Additional documentation -- [Official libGDX threading article.](https://github.com/libgdx/libgdx/wiki/Threading) +- [Official libGDX threading article.](https://libgdx.com/wiki/app/threading) - [Coroutines language reference.](https://kotlinlang.org/docs/reference/coroutines.html) - [Coroutines repository.](https://github.com/Kotlin/kotlin-coroutines) diff --git a/box2d/README.md b/box2d/README.md index 3d8853dd..7358da24 100644 --- a/box2d/README.md +++ b/box2d/README.md @@ -315,5 +315,5 @@ that originally inspired `ktx-box2d`. #### Additional documentation -- [Official libGDX *Box2D* article.](https://github.com/libgdx/libgdx/wiki/Box2d) +- [Official libGDX *Box2D* article.](https://libgdx.com/wiki/extensions/physics/box2d) - [Official *Box2D* website.](http://box2d.org/) diff --git a/collections/README.md b/collections/README.md index 3267f9c5..c91aa50a 100644 --- a/collections/README.md +++ b/collections/README.md @@ -36,7 +36,7 @@ its content. - Missing `addAll` and `removeAll` methods for arrays and iterables were added. - `iterate` method allows iterating over collection's elements, while providing reference to `MutableInterator`. Can be used to easily remove collection elements during iteration. -- `removeAll` and `retainAll` higher-order functions that work like collection extensions in Kotlin stdlib. A `Pool` can +- `removeAll` and `retainAll` higher-order functions that work like collection extensions in Kotlin stdlib. A `Pool` can optionally be passed to automatically free the removed items. - `transfer` extension method can be used to move elements from one array to another using a lambda predicate. - `map`, `filter`, `flatten` and `flatMap` methods that work like methods in Kotlin stdlib but return `GdxArray`. @@ -86,7 +86,7 @@ used to easily remove collection elements during iteration. libGDX features `ObjectMap` class, which works similarly to `HashMap`, but it reuses its iterators. - `ObjectMap` instances can be constructed with `gdxMapOf` methods, similarly to how you create `java.util` maps in Kotlin. -- `IdentityMap` instances can be constructed with `gdxIdentityMapOf` methods. +- `IdentityMap` instances can be constructed with `gdxIdentityMapOf` methods. - Basic support for optimized primitive `IntIntMap`, `IntFloatMap` and `IntMap` collections. - Null-safe `isEmpty()`, `isNotEmpty()` and `size()` methods where added. They allow you to inspect the collection even if the variable is a possible null. @@ -130,7 +130,7 @@ array[0] // "zero" array += "three" // array[3] == "three"; array.size == 4 array -= "three" // "three" in array == false; array.size == 3 array += arrayOf("three", "four") // array[3] == "three", array[4] = "four" - + val empty = gdxArrayOf() val arrayOfPrimitives = gdxIntArrayOf(1, 2, 3) @@ -180,10 +180,10 @@ but since it is written with Java, `ktx-collections` is arguably easier to use i is still worth looking into for its *lazy*, *disposable* and *immutable* collections. - [Koloboke](https://github.com/leventov/Koloboke) contains efficient implementations of sets and maps that can use unboxed primitive types as keys or values. Its API design and implementation is most likely significantly better and -more efficient than libGDX collections, it is also a major dependency due to the sheer amount of available collections +more efficient than libGDX collections, it is also a major dependency due to the sheer amount of available collections and its code generators. Note that Koloboke collections are compatible with `java.util` collections API, while libGDX collections are not - Koloboke maps and sets can fully benefit from Kotlin standard library utilities. #### Additional documentation -- [Official libGDX collections article.](https://github.com/libgdx/libgdx/wiki/Collections) +- [Official libGDX collections article.](https://libgdx.com/wiki/utils/collections) diff --git a/freetype-async/README.md b/freetype-async/README.md index b494eb7e..706d586a 100644 --- a/freetype-async/README.md +++ b/freetype-async/README.md @@ -2,7 +2,7 @@ # KTX: FreeType font asynchronous loading utilities -A tiny modules that makes it easier to use [`gdx-freetype`](https://github.com/libgdx/libgdx/wiki/Gdx-freetype) +A tiny modules that makes it easier to use [`gdx-freetype`](https://libgdx.com/wiki/extensions/gdx-freetype) library along with the coroutines-based `AssetStorage` from [`ktx-assets-async`](../assets-async). ### Why? @@ -218,11 +218,11 @@ fun loadFont(assetManager: AsyncAssetManager) { ### Alternatives FreeType font loaders can be registered manually. See -[this article](https://github.com/libgdx/libgdx/wiki/Managing-your-assets#loading-a-ttf-using-the-assethandler). +[this article](https://libgdx.com/wiki/managing-your-assets#loading-a-ttf-using-the-assethandler). `setLoader` method can be used to add new libGDX loaders to an `AssetStorage`. #### Additional documentation -- [Official `gdx-freetype` article.](https://github.com/libgdx/libgdx/wiki/Gdx-freetype) +- [Official `gdx-freetype` article.](https://libgdx.com/wiki/extensions/gdx-freetype) - [`ktx-async` module.](../async) - [`ktx-assets-async` module.](../assets-async) diff --git a/freetype/README.md b/freetype/README.md index 3b180be9..186f781e 100644 --- a/freetype/README.md +++ b/freetype/README.md @@ -2,7 +2,7 @@ # KTX: FreeType font utilities -A tiny modules that makes it easier to use [`gdx-freetype`](https://github.com/libgdx/libgdx/wiki/Gdx-freetype) library. +A tiny modules that makes it easier to use [`gdx-freetype`](https://libgdx.com/wiki/extensions/gdx-freetype) library. ### Why? @@ -141,9 +141,9 @@ This module uses [`ktx-assets`](../assets) internally to improve `AssetManager` ### Alternatives FreeType font loaders can be registered manually. See -[this article](https://github.com/libgdx/libgdx/wiki/Managing-your-assets#loading-a-ttf-using-the-assethandler). +[this article](https://libgdx.com/wiki/managing-your-assets#loading-a-ttf-using-the-assethandler). #### Additional documentation -- [`gdx-freetype` article.](https://github.com/libgdx/libgdx/wiki/Gdx-freetype) -- [`AssetManager` article.](https://github.com/libgdx/libgdx/wiki/Managing-your-assets#loading-a-ttf-using-the-assethandler) +- [`gdx-freetype` article.](https://libgdx.com/wiki/extensions/gdx-freetype) +- [`AssetManager` article.](https://libgdx.com/wiki/managing-your-assets#loading-a-ttf-using-the-assethandler) diff --git a/graphics/README.md b/graphics/README.md index 3e9bd18e..36f9b03d 100644 --- a/graphics/README.md +++ b/graphics/README.md @@ -6,7 +6,7 @@ General utilities for handling libGDX graphics-related API. ### Why? -While libGDX API is not particularly bad in this case and the **KTX** module provides only minor improvements, +While libGDX API is not particularly bad in this case and the **KTX** module provides only minor improvements, Kotlin build-in features can greatly simplify some common operations related to graphics and prevent some common bugs such as forgetting to start or end batch rendering. @@ -14,7 +14,7 @@ common bugs such as forgetting to start or end batch rendering. #### Miscellaneous utilities -- `use` inlined extension methods added to `Batch`, `ShaderProgram` and `GLFrameBuffer`. They allow safe omission of the +- `use` inlined extension methods added to `Batch`, `ShaderProgram` and `GLFrameBuffer`. They allow safe omission of the `begin()` and `end()` calls when using batches, shader programs and buffers. Note that a camera or a matrix can also be passed to selected extension methods to have it automatically applied as the projection matrix. - `begin` extension methods that automatically set projection matrix from a `Camera` or `Matrix4` were added to `Batch`. @@ -203,7 +203,7 @@ shapeRenderer.use(ShapeRenderer.ShapeType.Filled, camera) { */ ``` -Using `ShapeRenderer` with vectors: +Using `ShapeRenderer` with vectors: ```kotlin import com.badlogic.gdx.graphics.glutils.ShapeRenderer @@ -270,7 +270,7 @@ import ktx.graphics.center fun centerCamera(camera: OrthographicCamera) { // Sets position to the middle of the screen: camera.center() - + // Sets position to the middle of the chosen rectangle: camera.center(x = 100f, y = 100f, width = 800f, height = 800f) } @@ -324,7 +324,7 @@ library with some utilities similar to `ktx-graphics`. #### Additional documentation -- [`SpriteBatch` official article.](https://github.com/libgdx/libgdx/wiki/Spritebatch%2C-Textureregions%2C-and-Sprites) -- [Official article on shaders.](https://github.com/libgdx/libgdx/wiki/Shaders) -- [`ShapeRenderer` official article.](https://github.com/libgdx/libgdx/wiki/Rendering-shapes) -- [Official article on screenshots.](https://github.com/libgdx/libgdx/wiki/Taking-a-Screenshot) +- [`SpriteBatch` official article.](https://libgdx.com/wiki/graphics/2d/spritebatch-textureregions-and-sprites) +- [Official article on shaders.](https://libgdx.com/wiki/graphics/opengl-utils/shaders) +- [`ShapeRenderer` official article.](https://libgdx.com/wiki/graphics/opengl-utils/rendering-shapes) +- [Official article on screenshots.](https://libgdx.com/wiki/graphics/taking-a-screenshot) diff --git a/i18n/README.md b/i18n/README.md index bce1592f..7bf677ec 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -61,7 +61,7 @@ existing `.properties` bundle: ```groovy task nls << { - def project = 'core' // Will contain generated enum class. + def project = 'core' // Will contain generated enum class. def source = 'src/main/kotlin' // Kotlin source path of the project. def pack = 'com.your.company' // Enum target package. def name = 'Nls' // Enum class name. @@ -193,4 +193,4 @@ libGDX `I18NBundle` API. However, it requires creating views with HTML-like temp #### Additional documentation -- [`I18NBundle` article.](https://github.com/libgdx/libgdx/wiki/Internationalization-and-Localization) +- [`I18NBundle` article.](https://libgdx.com/wiki/internationalization-and-localization) diff --git a/inject/README.md b/inject/README.md index ba947211..f41a733e 100644 --- a/inject/README.md +++ b/inject/README.md @@ -160,7 +160,7 @@ fun create() { // Will construct a new instance of MyDependency with reflection // each time it is requested: bind() - + // Will construct a single instance of MyClass with MyDependency // taken from Context: bindSingleton() @@ -200,7 +200,7 @@ class Container: Disposable { } override fun dispose() { -+ context.remove() ++ context.remove() context.dispose() } } @@ -270,4 +270,4 @@ obviously expected to be more efficient. #### Additional documentation -- [Official reflection article.](https://github.com/libgdx/libgdx/wiki/Reflection) +- [Official reflection article.](https://libgdx.com/wiki/utils/reflection) diff --git a/json/README.md b/json/README.md index 58b162c2..13726854 100644 --- a/json/README.md +++ b/json/README.md @@ -8,7 +8,7 @@ Extension methods for libGDX JSON serialization API. The libGDX JSON reader and writer methods often consume `Class` parameters, which forces the `Type::class.java` syntax on Kotlin users. Fortunately, Kotlin brings reified generics which effectively -allow passing a `Class` parameter through a generic type. This module mostly offers extension methods +allow passing a `Class` parameter through a generic type. This module mostly offers extension methods with reified generics to avoid using `::class.java` in your code, as well as to allow type inference and better type safety. Additionally, it provides a couple of classes to facilitate creation of custom serializers. @@ -47,7 +47,7 @@ fun deserialize(file: FileHandle): MyClass { return json.fromJson(MyClass::class.java, file) // Using KTX Kotlin extensions: - return json.fromJson(file) + return json.fromJson(file) } ``` @@ -178,7 +178,7 @@ serialization libraries. It also accepts and produces corrupted JSON files by de since it omits quotation marks, which might be problematic when integrating with external services. -However, if your project is simple enough and you want to avoid including additional JSON +However, if your project is simple enough and you want to avoid including additional JSON serialization libraries in your game, official libGDX `Json` can be enough. In most other cases, you should probably look into other popular serialization libraries: @@ -190,4 +190,4 @@ to name a few. #### Additional documentation -- [Official `Json` usage article.](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON) +- [Official `Json` usage article.](https://libgdx.com/wiki/utils/reading-and-writing-json) diff --git a/log/README.md b/log/README.md index 9da12803..6eff8a00 100644 --- a/log/README.md +++ b/log/README.md @@ -169,4 +169,4 @@ templates to avoid creation of new strings (unless necessary). However, it still #### Additional documentation -- [Official libGDX logging article.](https://github.com/libgdx/libgdx/wiki/Logging) +- [Official libGDX logging article.](https://libgdx.com/wiki/app/logging) diff --git a/math/README.md b/math/README.md index 75fe0dd5..43af8e80 100644 --- a/math/README.md +++ b/math/README.md @@ -60,7 +60,7 @@ mutation methods return new vectors instead of mutating the objects. - `withAngleDeg()` and `withAngleRad` replace `setAngle` and `setAngleRad` and return a new vector of same length and the given angle to x-axis. - `cpy` is deprecated and is not necessary. Immutable vectors can be safely shared. However, since `ImmutableVector` is - a `data class`, there is a `copy(x, y)` method available allowing to easily create new vectors based on existing ones. + a `data class`, there is a `copy(x, y)` method available allowing to easily create new vectors based on existing ones. - `set(x, y)` and `setZero()` are not provided. - Functions dealing with angles in degree are suffixed with `Deg` and all returns values between `-180` and `+180`. - All angle functions return the angle toward positive y-axis. @@ -104,7 +104,7 @@ vector1 += ImmutableVector2.Y vector1 *= 3f val vector2 = vector1.withClamp(0f, 1f) * 5f // `vector1` is not modified. -``` +``` Creating convenience type alias to ease the use of immutable vectors: @@ -166,15 +166,15 @@ new instances of matrices. - `Matrix4` instances can be multiplied with a `Vector3` using `*` operator. - `Matrix4` instances can be destructed into sixteen float variables (each representing one of its cells) thanks to the `component1()` - `component16()` operator functions. - + #### Ranges -- The `amid` infix function for Int and Float allows easy creation of a range by using a center and a tolerance. Such a +- The `amid` infix function for Int and Float allows easy creation of a range by using a center and a tolerance. Such a definition is a convenient way to think about a range from which random values will be selected. -- The four arithmetic operators are available for easily shifting or scaling ranges. This allows intuitive modification -of ranges in code, which can be useful for code clarity when defining a range for random number selection, or for +- The four arithmetic operators are available for easily shifting or scaling ranges. This allows intuitive modification +of ranges in code, which can be useful for code clarity when defining a range for random number selection, or for rapidly iterating a design. -- `IntRange.random(random: java.util.Random)` allows using a Java Random to select a number from the range, and is +- `IntRange.random(random: java.util.Random)` allows using a Java Random to select a number from the range, and is provided in case there is a need to use the `MathUtils.random` instance or an instance of libGDX's fast RandomXS128. - `ClosedRange.random()` allows a evenly distributed random number to be selected from a range (but treating the `endInclusive` as exclusive for simplicity). @@ -235,5 +235,5 @@ lib by `g-truc`. #### Additional documentation -- [Official libGDX math utilities article.](https://github.com/libgdx/libgdx/wiki/Math-utilities) -- [`Vectors` and `Matrices` article.](https://github.com/libgdx/libgdx/wiki/Vectors%2C-matrices%2C-quaternions) +- [Official libGDX math utilities article.](https://libgdx.com/wiki/math-utils/math-utilities) +- [`Vectors` and `Matrices` article.](https://libgdx.com/wiki/math-utils/vectors-matrices-quaternions) diff --git a/preferences/README.md b/preferences/README.md index f2c54e29..8f3af4f6 100644 --- a/preferences/README.md +++ b/preferences/README.md @@ -6,7 +6,7 @@ Utilities and extension function for libGDX preferences. ### Why? -Unfortunately, libGDX [`Preferences`](https://github.com/libgdx/libgdx/wiki/Preferences) do not provide a consistent +Unfortunately, libGDX [`Preferences`](https://libgdx.com/wiki/preferences) do not provide a consistent API for setting and getting values, and they do not support Kotlin operators either. Since in principle `Preferences` work very similarly to a `Map`, ideally they should support a similar syntax - especially since in Kotlin you can take advantage of the square bracket operators. @@ -16,8 +16,8 @@ especially since in Kotlin you can take advantage of the square bracket operator - Values can be set and read via the new `set` and `get` operators using the square bracket (`[]`) syntax. It is no longer necessary to call type specific methods like `putString` or `getBoolean` for each type separately. `set` and `get` support objects of any type. If the type is not of `String`, `Boolean`, -`Int`, `Float`, `Double` or `Long` type, the value is stored and retrieved using -[JSON](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON) serialization. +`Int`, `Float`, `Double` or `Long` type, the value is stored and retrieved using +[JSON](https://libgdx.com/wiki/utils/reading-and-writing-json) serialization. - Note that `Double` type is not supported by libGDX `Preferences` and converted to `Float` instead. Use explicit casts (`toFloat()`) or wrap the value with a JSON-serializable object when storing numbers that do not fit in a `Float`. @@ -73,7 +73,7 @@ import ktx.preferences.* /** * This class will be serialized. - * + * * Remember to add default values for each variable, * so the class remains JSON-serializable! */ @@ -120,7 +120,7 @@ fun saveInPreferencesWithFlush( this["SomeFloat"] = float this["SomeBoolean"] = bool this["SomeInt"] = int - this["SomeLong"] = long + this["SomeLong"] = long // preferences.flush() will be called automatically after this block. } } @@ -162,5 +162,5 @@ fun addPreferencesUsingKotlinPairs(preferences: Preferences) { ### Additional documentation -- [Official libGDX `Preferences` article](https://github.com/libgdx/libgdx/wiki/Preferences). -- [Official libGDX `Json` article](https://github.com/libgdx/libgdx/wiki/Reading-and-writing-JSON). +- [Official libGDX `Preferences` article](https://libgdx.com/wiki/preferences). +- [Official libGDX `Json` article](https://libgdx.com/wiki/utils/reading-and-writing-json). diff --git a/reflect/README.md b/reflect/README.md index 2e4bd871..c5fdb757 100644 --- a/reflect/README.md +++ b/reflect/README.md @@ -231,4 +231,4 @@ If cross-platform compatibility is not a concern, Kotlin and Java reflection API #### Additional documentation -- [Official reflection article.](https://github.com/libgdx/libgdx/wiki/Reflection) +- [Official reflection article.](https://libgdx.com/wiki/utils/reflection) diff --git a/reflect/src/main/kotlin/ktx/reflect/reflect.kt b/reflect/src/main/kotlin/ktx/reflect/reflect.kt index 62478d19..a4bd4e8e 100644 --- a/reflect/src/main/kotlin/ktx/reflect/reflect.kt +++ b/reflect/src/main/kotlin/ktx/reflect/reflect.kt @@ -26,7 +26,7 @@ solely by reflection must be listed in the robovm.xml file within the ForceLinkClasses section in order to work on iOS. Further reading: -* https://github.com/libgdx/libgdx/wiki/Reflection +* https://libgdx.com/wiki/utils/reflection * https://kotlinlang.org/docs/opt-in-requirements.html """ ) diff --git a/scene2d/README.md b/scene2d/README.md index 408fb266..f7313604 100644 --- a/scene2d/README.md +++ b/scene2d/README.md @@ -196,7 +196,7 @@ Also, you do not have to worry to accidentally changing properties of nested act that during compilation: ```kotlin -scene2d.table { +scene2d.table { label("This would not compile") { pad(4f) // !!! Compilation error: `pad` belongs to the `table`, not `label`. } @@ -440,7 +440,7 @@ import com.badlogic.gdx.scenes.scene2d.Stage import ktx.scene2d.* fun addActorsToStage(stage: Stage) { - stage.actors { + stage.actors { table { label("This table will be added to the stage.") } @@ -460,7 +460,7 @@ import ktx.scene2d.* // actors possible: val myLabel: Label -val myTable = scene2d.table { +val myTable = scene2d.table { myLabel = label("Kotlin contracts make it possible!") } ``` @@ -516,7 +516,7 @@ val table = scene2d.table { cell.expand() } - // Cells are available only for direct children of tables (or its extensions). + // Cells are available only for direct children of tables (or its extensions). stack { // These would not compile: label("Invalid.").cell(expand = true) // Not in a table! @@ -589,7 +589,7 @@ val table = scene2d.table { }.cell(row = true) } -val withoutBuildingBlocks = scene2d.table { +val withoutBuildingBlocks = scene2d.table { // You can also define the widgets with lists of items: listWidgetOf(GdxArray.with("First", "Second", "Third")) selectBoxOf(GdxArray.with("First", "Second", "Third")) @@ -605,12 +605,12 @@ Adding tooltips to actors: ```kotlin import ktx.scene2d.* -val labelWithTooltips = scene2d { +val labelWithTooltips = scene2d { label("Text") { textTooltip(text = "This is a simple text tooltip!") { // You can customize tooltip's Label here. } - tooltip { + tooltip { label("This is a complex tooltip using a table!").cell(row = true) label("It can have multiple widgets and custom layouts.") } @@ -625,10 +625,10 @@ import ktx.scene2d.* scene2d.table { // Extract a named asset from a Skin: - image("button") + image("button") - // Or use the assets directly: - image(Drawable(...)) + // Or use the assets directly: + image(Drawable(...)) image(NinePatch(...)) image(TextureRegion(...)) image(Texture(...)) @@ -715,10 +715,10 @@ inline fun KWidget.myCustomWidget( // Creating our custom widget with ktx-scene2d DSL: fun usageExample() { - scene2d.myCustomWidget { + scene2d.myCustomWidget { // Customize your widget here! setFillParent(true) - + // Since we implemented KTable, this actor can have children: label("A child of the custom widget!").cell(grow = true) } @@ -760,7 +760,7 @@ The migration is pretty straightforward: add `scene2d.` prefix to all root actor the new `Stage.actors` extension method to add actors directly to a `Stage`. Note that nested actor definitions do not require any changes. -Only 2 factory methods were changed significantly: `listWidget` and `selectBox`. Now they have only a single +Only 2 factory methods were changed significantly: `listWidget` and `selectBox`. Now they have only a single generic parameter - type of the items - and no longer consume `Cell` or `Node` instances in their building blocks. Instead, you have to call `cell`, `inCell`, `node` or `inNode` outside of their building blocks to configure the layout. @@ -770,9 +770,9 @@ Further KTX releases do not contain the deprecated functions. ### Alternatives -- Creating layouts with [Scene2D](https://github.com/libgdx/libgdx/wiki/Scene2d) directly in Kotlin or Java. +- Creating layouts with [Scene2D](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d) directly in Kotlin or Java. - [VisUI](https://github.com/kotcrab/vis-editor/wiki/VisUI) greatly extends -[Scene2D](https://github.com/libgdx/libgdx/wiki/Scene2d.ui) API, but lacks first-class Kotlin support. +[Scene2D](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d-ui) API, but lacks first-class Kotlin support. - [LML](https://github.com/czyzby/gdx-lml/tree/master/lml) allows building `Scene2D` views using HTML-like syntax. It also features a [VisUI extension](https://github.com/czyzby/gdx-lml/tree/master/lml-vis). However, it lacks first-class Kotlin support and the flexibility of a programming language. @@ -781,7 +781,7 @@ first-class Kotlin support and the flexibility of a programming language. #### Additional documentation -- [Scene2D article.](https://github.com/libgdx/libgdx/wiki/Scene2d) -- [Scene2D UI article.](https://github.com/libgdx/libgdx/wiki/Scene2d.ui) -- [`Table` article.](https://github.com/libgdx/libgdx/wiki/Table) -- [`Skin` article.](https://github.com/libgdx/libgdx/wiki/Skin) +- [Scene2D article.](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d) +- [Scene2D UI article.](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d-ui) +- [`Table` article.](https://libgdx.com/wiki/graphics/2d/scene2d/table) +- [`Skin` article.](https://libgdx.com/wiki/graphics/2d/scene2d/skin) diff --git a/style/README.md b/style/README.md index d02726a9..4f86ff57 100644 --- a/style/README.md +++ b/style/README.md @@ -16,7 +16,7 @@ JSON format also suffers from no extension mechanism, which leads to data duplic Kotlin type-safe builders can make style definitions less verbose than usual, as easily readable as JSON and basically as fast to parse as hand-written Java code thanks to inlined functions and no reflection usage. By converting your JSON skins into `ktx-style` builders, you speed up your application startup time. - + ### Guide `Skin` instances can be constructed with `skin` functions, both of which accept a Kotlin-style init block. @@ -172,7 +172,7 @@ import ktx.style.* skin(myAtlas) { // Skin is available under `it` parameter, so you can access other resources. - button { + button { up = it["buttonUp"] // Automatically extracts drawable with buttonUp name. down = it["buttonDown"] } @@ -334,12 +334,12 @@ skin(myAtlas) { } ``` -What is best about it, enums do not necessarily make your code _longer_ or less readable - all while having the -advantage of powerful code completion of your IDE of choice and validation at compile time. As long as you +What is best about it, enums do not necessarily make your code _longer_ or less readable - all while having the +advantage of powerful code completion of your IDE of choice and validation at compile time. As long as you do not need to create assets at runtime with custom string IDs, we encourage you to store your drawables, fonts, colors and styles names as enums to ensure safely at compile time. -The advantage of using an `enum` over a "standard" singleton (`object`) with `String` properties or `String` +The advantage of using an `enum` over a "standard" singleton (`object`) with `String` properties or `String` constants is that you can easily extract a list of all values from an `enum`, while getting all fields from an object or constants from a package requires reflection. @@ -365,4 +365,4 @@ suffers from the same issues as regular skin JSON. #### Additional documentation -- [`Skin` article.](https://github.com/libgdx/libgdx/wiki/Skin) +- [`Skin` article.](https://libgdx.com/wiki/graphics/2d/scene2d/skin) diff --git a/tiled/README.md b/tiled/README.md index 5a3002a0..91a2dc7d 100644 --- a/tiled/README.md +++ b/tiled/README.md @@ -47,7 +47,7 @@ New extension fields include: Almost all objects are related to a shape except for `TextureMapObject`. Sometimes you need access to these shapes like e.g. when creating [Box2D](../box2d) bodies out of those objects. For that reason a new extension field was added: -- `shape`: returns the `Shape2D` of a map object. This can either be a `Rectangle`, `Circle`, +- `shape`: returns the `Shape2D` of a map object. This can either be a `Rectangle`, `Circle`, `Ellipse`, `Polyline` or `Polygon`. If there is an object that is not linked to a shape then a `MissingShapeException` is thrown. @@ -232,7 +232,7 @@ val map: TiledMap = getTiledMap() // Iterate over all object layers and parse them. // Note that println is only called with layers of the exact MapLayer type. -// For example, TiledMapTileLayer - which is a subclass of MapLayer - does not +// For example, TiledMapTileLayer - which is a subclass of MapLayer - does not // have this exact class and will not be matched. map.forEachLayer { layer -> println(layer) @@ -252,7 +252,7 @@ if (map.layers.isNotEmpty()) { map.layers.forEach { layer -> if (layer.objects.isEmpty()) { // nothing to do if there are no objects - return@forEach + return@forEach } parseObjects(layer.objects) } @@ -262,5 +262,5 @@ if (map.layers.isNotEmpty()) { #### Additional documentation - [Official Tiled website.](https://www.mapeditor.org/) -- [Official libGDX tile maps article.](https://github.com/libgdx/libgdx/wiki/Tile-maps) +- [Official libGDX tile maps article.](https://libgdx.com/wiki/graphics/2d/tile-maps) - [Official Tiled documentation.](https://doc.mapeditor.org/en/stable/) diff --git a/vis-style/README.md b/vis-style/README.md index d8b7ad5a..bf888b90 100644 --- a/vis-style/README.md +++ b/vis-style/README.md @@ -81,4 +81,4 @@ to use this library. #### Additional documentation - [VisUI wiki.](https://github.com/kotcrab/vis-editor/wiki/VisUI) -- [`Skin` article.](https://github.com/libgdx/libgdx/wiki/Skin) +- [`Skin` article.](https://libgdx.com/wiki/graphics/2d/scene2d/skin) diff --git a/vis/README.md b/vis/README.md index a06a5d74..276b431f 100644 --- a/vis/README.md +++ b/vis/README.md @@ -113,7 +113,7 @@ fun createMenu(stage: Stage) { } } } - menu.showMenu(stage, 0f, 0f) + menu.showMenu(stage, 0f, 0f) } ``` @@ -357,8 +357,8 @@ Additionally to changes that apply to `ktx-scene2d`, `ktx-vis` was rewritten to Notable changes include: * All factory methods for VisUI widgets are now inlined. -* `vis` prefix was added to the names of some VisUI widget factory methods to avoid clashes with Scene2D -and better reflect the widget class names. A complete list is available in the change log. +* `vis` prefix was added to the names of some VisUI widget factory methods to avoid clashes with Scene2D +and better reflect the widget class names. A complete list is available in the change log. * Parental actors including `collapsible`, `dragPane`, `horizontalCollapsible`, `visScrollPane`, `visSplitPane` and `multiSplitPane` now do not require passing widgets to their factory methods. Instead, widgets are either automatically created or can be defined as nested children with the same DSL. @@ -383,6 +383,6 @@ first-class Kotlin support and the flexibility of a programming language. #### Additional documentation - [VisUI wiki.](https://github.com/kotcrab/vis-editor/wiki/VisUI) -- [Scene2D article.](https://github.com/libgdx/libgdx/wiki/Scene2d) -- [Scene2D UI article.](https://github.com/libgdx/libgdx/wiki/Scene2d.ui) -- [`Table` article.](https://github.com/libgdx/libgdx/wiki/Table) +- [Scene2D article.](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d) +- [Scene2D UI article.](https://libgdx.com/wiki/graphics/2d/scene2d/scene2d-ui) +- [`Table` article.](https://libgdx.com/wiki/graphics/2d/scene2d/table) From 5c55e2cfe706c15955fe654ebbfa3faa58ea9693 Mon Sep 17 00:00:00 2001 From: MJ Date: Wed, 19 Jan 2022 13:20:37 +0100 Subject: [PATCH 11/13] Tree node selection listener. #398 --- .github/CONTRIBUTORS.md | 4 ++ CHANGELOG.md | 4 ++ actors/README.md | 3 +- actors/src/main/kotlin/ktx/actors/events.kt | 24 +++++++----- .../src/test/kotlin/ktx/actors/EventsTest.kt | 37 +++++++++++++++++-- scene2d/src/main/kotlin/ktx/scene2d/widget.kt | 2 +- vis/src/main/kotlin/ktx/scene2d/vis/widget.kt | 3 +- 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/.github/CONTRIBUTORS.md b/.github/CONTRIBUTORS.md index 6e2948ac..e232c650 100644 --- a/.github/CONTRIBUTORS.md +++ b/.github/CONTRIBUTORS.md @@ -89,6 +89,10 @@ Project contributors listed chronologically. * Contributed an initial implementation of reflection-based component binding for the [inject module](../inject). * [@fejd](https://github.com/fejd) * Contributed utilities to the [collections module](../collections). +* [@manabreak](https://github.com/manabreak) + * Contributed utilities to the [actors module](../actors). +* [@crykn](https://github.com/crykn) + * Updated links to the new libGDX wiki. ### Metrics diff --git a/CHANGELOG.md b/CHANGELOG.md index 498002ad..d472cfd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob - **[UPDATE]** Updated to Kotlin 1.6.10. - **[UPDATE]** Updated to Kotlin Coroutines 1.6.0. +- **[MISC]** Links to the libGDX wiki were updated. +- **[CHANGE]** (`ktx-scene2d`) The generic `Node` type of `KTreeWidget` was changed to `KNode<*>`. +- **[FEATURE]** Added `Tree.onSelectionChange` extension method that attaches a `ChangeListener` to a `Tree`. - **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime. - `evaluate(String)`: compiles and executes a script passed as a string. - `evaluate(FileHandle)`: compiles and executes a script from the selected file. @@ -16,6 +19,7 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob - `importAll(vararg String)`, `importAll(Iterable)`: adds the selected imports to the script context. - `setPackage(String)`: sets the package for the scripts. - `onItemClick(Node)`: adds a listener that gets invoked when `Node` in a `Tree` gets clicked. +- **[CHANGE]** (`ktx-vis`) The generic `Node` type of `KVisTree` was changed to `KNode<*>`. #### 1.10.0-b4 diff --git a/actors/README.md b/actors/README.md index def7fd89..ed86a428 100644 --- a/actors/README.md +++ b/actors/README.md @@ -42,7 +42,8 @@ and `onKeyboardFocusEvent` `Actor` extension methods were added. They consume th parameters. Both listener factory variants are inlined, but the ones ending with *Event* provide more lambda parameters and allow to inspect the original `Event` instance that triggered the listener. Regular listener factory methods should be enough for most use cases. -- Lambda-compatible `Tree.onItemClick` method was added. Allows listening to `Node`s being clicked in `Tree` structures. +- Lambda-compatible `Tree.onSelectionChange` method was added. Attaches a listener invoked each time a `Tree`'s node +selection is modified. #### Actions diff --git a/actors/src/main/kotlin/ktx/actors/events.kt b/actors/src/main/kotlin/ktx/actors/events.kt index e035fcf3..e94c49bf 100644 --- a/actors/src/main/kotlin/ktx/actors/events.kt +++ b/actors/src/main/kotlin/ktx/actors/events.kt @@ -14,6 +14,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent.Type.keyboard import com.badlogic.gdx.scenes.scene2d.utils.FocusListener.FocusEvent.Type.scroll +import com.badlogic.gdx.scenes.scene2d.utils.Selection /** * Attaches a [ChangeListener] to this actor. @@ -90,17 +91,22 @@ inline fun T.onClickEvent( } /** - * Attaches a [ClickListener] to this tree. - * @param lsitener invoked each time a node in this tree is clicked. Consumes the triggered [InputEvent] and the - * [Tree] the listener was originally attached to as `this`. The received Node is the node that was clicked. - * @return [ClickListener] instance. + * Attaches a [ChangeListener] to this [Tree]. + * @param listener invoked each time the node [Selection] is changed. Receives the [Selection] object + * which can be used to obtain all selected items with [Selection.items] or the latest selected item + * with [Selection.getLastSelected]. + * @return [ChangeListener] instance. */ -inline fun > T.onItemClick(crossinline listener: ((Tree.Node<*, *, *>) -> Unit)): ClickListener { - val clickListener = object : ClickListener() { - override fun clicked(event: InputEvent?, x: Float, y: Float) = listener(selectedNode) +inline fun > Tree.onSelectionChange( + crossinline listener: ((Selection) -> Unit) +): ChangeListener { + val changeListener = object : ChangeListener() { + override fun changed(event: ChangeEvent, actor: Actor) { + listener(this@onSelectionChange.selection) + } } - addListener(clickListener) - return clickListener + addListener(changeListener) + return changeListener } /** diff --git a/actors/src/test/kotlin/ktx/actors/EventsTest.kt b/actors/src/test/kotlin/ktx/actors/EventsTest.kt index 5f5ce899..215717be 100644 --- a/actors/src/test/kotlin/ktx/actors/EventsTest.kt +++ b/actors/src/test/kotlin/ktx/actors/EventsTest.kt @@ -17,8 +17,10 @@ import io.kotlintest.mock.mock import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull +import org.junit.Assert.assertSame import org.junit.Assert.assertTrue import org.junit.Test +import java.util.concurrent.atomic.AtomicInteger /** * Tests events and listeners utilities. @@ -81,19 +83,48 @@ class EventsTest { assertTrue(listener in actor.listeners) } + class SampleNode : Tree.Node(mock()) + @Test - fun `should attach ClickListener to a Tree consuming InputEvent with clicked Node`() { + fun `should attach ChangeListener to a Tree consuming Selection with the selected Nodes`() { val style = mock() style.plus = mock() style.minus = mock() - val tree = Tree, Any>(style) + val tree = Tree(style) - val listener = tree.onItemClick { } + val listener = tree.onSelectionChange {} assertNotNull(listener) assertTrue(listener in tree.listeners) } + @Test + fun `should invoke attached ChangeListener when tree Selection changes`() { + val style = mock() + style.plus = mock() + style.minus = mock() + val tree = Tree(style) + tree.selection.setProgrammaticChangeEvents(true) + val nodes = Array(3) { SampleNode() } + val selected = SampleNode() + nodes.forEach(tree::add) + tree.add(selected) + val executions = AtomicInteger() + val selectedNodes = mutableListOf() + tree.selection.clear() + tree.onSelectionChange { selection -> + executions.incrementAndGet() + selectedNodes.clear() + selectedNodes.addAll(selection.items()) + } + + tree.selection.add(selected) + + assertEquals(1, executions.get()) + assertEquals(1, selectedNodes.size) + assertSame(selected, selectedNodes.first()) + } + @Test fun `should attach InputListener for touchDown`() { val actor = Actor() diff --git a/scene2d/src/main/kotlin/ktx/scene2d/widget.kt b/scene2d/src/main/kotlin/ktx/scene2d/widget.kt index 855310b4..d09f8279 100644 --- a/scene2d/src/main/kotlin/ktx/scene2d/widget.kt +++ b/scene2d/src/main/kotlin/ktx/scene2d/widget.kt @@ -453,7 +453,7 @@ class KTextButton(text: String, skin: Skin, style: String) : TextButton(text, sk /** Extends [Tree] API with type-safe widget builders. */ @Scene2dDsl -class KTreeWidget(skin: Skin, style: String) : Tree, Any?>(skin, style), KTree { +class KTreeWidget(skin: Skin, style: String) : Tree, Any?>(skin, style), KTree { override fun add(actor: A): KNode { val node = KNode(actor) add(node) diff --git a/vis/src/main/kotlin/ktx/scene2d/vis/widget.kt b/vis/src/main/kotlin/ktx/scene2d/vis/widget.kt index afb48e79..1fa1777f 100644 --- a/vis/src/main/kotlin/ktx/scene2d/vis/widget.kt +++ b/vis/src/main/kotlin/ktx/scene2d/vis/widget.kt @@ -7,7 +7,6 @@ import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Container import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.scenes.scene2d.ui.Tree import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.GdxRuntimeException import com.kotcrab.vis.ui.VisUI @@ -91,7 +90,7 @@ class KVisImageTextButton(text: String, styleName: String) : VisImageTextButton( /** Extends [VisTree] with type-safe widget builders. */ @Scene2dDsl -class KVisTree(styleName: String) : VisTree, Any?>(styleName), KTree { +class KVisTree(styleName: String) : VisTree, Any?>(styleName), KTree { override fun add(actor: T): KNode { val node = KNode(actor) add(node) From 85e63f8b3d1ae2befd0840375c8a9503f704b36a Mon Sep 17 00:00:00 2001 From: MJ Date: Wed, 19 Jan 2022 13:28:40 +0100 Subject: [PATCH 12/13] KTX version changed to 1.10.0-rc1. #407 --- CHANGELOG.md | 3 ++- README.md | 8 ++++---- version.txt | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d472cfd8..9a60cd49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob/master/CHANGES)._ -#### 1.10.0-SNAPSHOT +#### 1.10.0-rc1 - **[UPDATE]** Updated to Kotlin 1.6.10. - **[UPDATE]** Updated to Kotlin Coroutines 1.6.0. - **[MISC]** Links to the libGDX wiki were updated. +- **[MISC]** Stable **KTX** releases are now marked with the `-rc` suffix. - **[CHANGE]** (`ktx-scene2d`) The generic `Node` type of `KTreeWidget` was changed to `KNode<*>`. - **[FEATURE]** Added `Tree.onSelectionChange` extension method that attaches a `ChangeListener` to a `Tree`. - **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime. diff --git a/README.md b/README.md index b92c66bd..0654ddcd 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ in your `build.gradle` file: // Groovy DSL: ext { // Update this version to match the latest KTX release: - ktxVersion = '1.10.0-b4' + ktxVersion = '1.10.0-rc1' } dependencies { @@ -91,7 +91,7 @@ dependencies { // Kotlin DSL: // Update this version to match the latest KTX release: -val ktxVersion = "1.10.0-b4" +val ktxVersion = "1.10.0-rc1" dependencies { api(group = "io.github.libktx", name = "ktx-app", version = ktxVersion) @@ -111,8 +111,8 @@ reused throughout the build files. This will speed up updating of your project i #### Versioning **KTX** versions match the libGDX versions that they were compiled against. `$ktxVersion` will usually match your libGDX -version, but it might end with `-b` postfix if it is a beta release, or `-SNAPSHOT` if you are using the development -branch. +version, but it might end with `-rc` suffix if it is a stable release, or `-SNAPSHOT` if you are using the development +branch. Older **KTX** releases use the `-b` suffix to mark milestone releases. You can browse through our official releases [on Maven](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.github.libktx%22) and [on GitHub](https://github.com/libktx/ktx/releases). diff --git a/version.txt b/version.txt index 8c29cb41..70cd4f3f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.10.0-SNAPSHOT +1.10.0-rc1 From 526f46e497c9bd5e0a2e784e504e5fd495aebc01 Mon Sep 17 00:00:00 2001 From: MJ Date: Wed, 19 Jan 2022 14:07:52 +0100 Subject: [PATCH 13/13] Donations setup. #404 --- .github/CONTRIBUTING.md | 6 ++++++ .github/FUNDING.yml | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0e343336..9be9cfdc 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -40,6 +40,12 @@ please check the `README.md` file of the module, and add description of your ch should include a usage example in the module guide. Make sure to add all the necessary imports in the usage examples in `README.md` files to make it easier to try them out. +## Donations + + + Contribute on OpenCollective + + ## Working from sources ```bash diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..22d49e0f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,11 @@ +github: [czyzby] +# patreon: # Replace with a single Patreon username +open_collective: ktx +# ko_fi: # Replace with a single Ko-fi username +# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +# liberapay: # Replace with a single Liberapay username +# issuehunt: # Replace with a single IssueHunt username +# otechie: # Replace with a single Otechie username +# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']