From 0c769d8016dd3beff723e28b4a2374cdebcac944 Mon Sep 17 00:00:00 2001 From: soywiz Date: Thu, 12 Dec 2019 19:56:11 +0100 Subject: [PATCH] Updated KorGE to 1.5.0c --- build.gradle | 2 +- gradle.properties | 5 +- sample-3d/src/commonMain/kotlin/main.kt | 6 +- sample-3d/src/commonMain/kotlin/utils.kt | 2 +- sample-atlas/src/commonTest/kotlin/test.kt | 6 +- sample-box2d/src/commonMain/kotlin/Sample1.kt | 118 ++++++----------- .../src/commonMain/resources/simple.voice.mp3 | Bin 40161 -> 0 bytes .../src/commonMain/kotlin/main.kt | 3 +- .../com/soywiz/korge/newui/DefaultUISkin.kt | 64 --------- .../kotlin/com/soywiz/korge/newui/UIButton.kt | 106 --------------- .../com/soywiz/korge/newui/UICheckBox.kt | 59 --------- .../com/soywiz/korge/newui/UIComboBox.kt | 95 -------------- .../com/soywiz/korge/newui/UIObservable.kt | 18 --- .../com/soywiz/korge/newui/UIProgressBar.kt | 39 ------ .../com/soywiz/korge/newui/UIScrollBar.kt | 124 ------------------ .../soywiz/korge/newui/UIScrollableArea.kt | 75 ----------- .../kotlin/com/soywiz/korge/newui/UISkin.kt | 26 ---- .../kotlin/com/soywiz/korge/newui/UIView.kt | 60 --------- 18 files changed, 53 insertions(+), 755 deletions(-) delete mode 100644 sample-lipsync/src/commonMain/resources/simple.voice.mp3 delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/DefaultUISkin.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIButton.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UICheckBox.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIComboBox.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIObservable.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIProgressBar.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollBar.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollableArea.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UISkin.kt delete mode 100644 sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIView.kt diff --git a/build.gradle b/build.gradle index 9e7001d..a5ba1ee 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,6 @@ buildscript { mavenCentral() } dependencies { - classpath("com.soywiz.korlibs.korge.plugins:korge-gradle-plugin:1.4.3c") + classpath("com.soywiz.korlibs.korge.plugins:korge-gradle-plugin:$korgePluginVersion") } } diff --git a/gradle.properties b/gradle.properties index 4c08830..cba0e30 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,6 @@ +korgePluginVersion=1.5.0c + org.gradle.jvmargs=-Xmx1536m org.gradle.parallel=true -#disable.kotlin.native=true +org.gradle.parallel.intra=true +org.gradle.configureondemand=true diff --git a/sample-3d/src/commonMain/kotlin/main.kt b/sample-3d/src/commonMain/kotlin/main.kt index 23aac15..13191ea 100644 --- a/sample-3d/src/commonMain/kotlin/main.kt +++ b/sample-3d/src/commonMain/kotlin/main.kt @@ -5,9 +5,9 @@ import com.soywiz.korge.render.* import com.soywiz.korge.scene.* import com.soywiz.korge.tween.* import com.soywiz.korge.view.* -import com.soywiz.korge3d.experimental.* -import com.soywiz.korge3d.experimental.animation.* -import com.soywiz.korge3d.experimental.format.* +import com.soywiz.korge3d.* +import com.soywiz.korge3d.animation.* +import com.soywiz.korge3d.format.* import com.soywiz.korim.color.* import com.soywiz.korim.format.* import com.soywiz.korinject.* diff --git a/sample-3d/src/commonMain/kotlin/utils.kt b/sample-3d/src/commonMain/kotlin/utils.kt index e5b46cc..53a96c0 100644 --- a/sample-3d/src/commonMain/kotlin/utils.kt +++ b/sample-3d/src/commonMain/kotlin/utils.kt @@ -3,7 +3,7 @@ import com.soywiz.korge.input.* import com.soywiz.korge.scene.* import com.soywiz.korge.tween.* import com.soywiz.korge.view.* -import com.soywiz.korge3d.experimental.* +import com.soywiz.korge3d.* import com.soywiz.korim.color.* import com.soywiz.korio.async.* import com.soywiz.korma.geom.* diff --git a/sample-atlas/src/commonTest/kotlin/test.kt b/sample-atlas/src/commonTest/kotlin/test.kt index 4710873..068bd20 100644 --- a/sample-atlas/src/commonTest/kotlin/test.kt +++ b/sample-atlas/src/commonTest/kotlin/test.kt @@ -19,9 +19,9 @@ class AtlasTest : ViewsForTesting() { fun testAtlas() = suspendTest { val atlas = resourcesVfs["logos.atlas.json"].readAtlas(views) assertEquals(3, atlas.textures.size) - assertEquals(Size(66, 66), atlas.textures["korau.png"]!!.texture.size) - assertEquals(Size(66, 66), atlas.textures["korge.png"]!!.texture.size) - assertEquals(Size(66, 66), atlas.textures["korim.png"]!!.texture.size) + assertEquals(Size(64, 64), atlas.textures["korau.png"]!!.texture.size) + assertEquals(Size(64, 64), atlas.textures["korge.png"]!!.texture.size) + assertEquals(Size(64, 64), atlas.textures["korim.png"]!!.texture.size) } private val BmpSlice.size get() = Size(width, height) diff --git a/sample-box2d/src/commonMain/kotlin/Sample1.kt b/sample-box2d/src/commonMain/kotlin/Sample1.kt index 6200a50..84c95e6 100644 --- a/sample-box2d/src/commonMain/kotlin/Sample1.kt +++ b/sample-box2d/src/commonMain/kotlin/Sample1.kt @@ -1,106 +1,66 @@ import com.soywiz.korge.* -import com.soywiz.korge.admob.* import com.soywiz.korge.box2d.* -import com.soywiz.korge.input.* import com.soywiz.korge.view.* import com.soywiz.korgw.* import com.soywiz.korim.color.* import com.soywiz.korim.format.* -import com.soywiz.korim.vector.* -import com.soywiz.korio.async.* import com.soywiz.korio.file.std.* -import com.soywiz.korio.lang.* -import com.soywiz.korma.geom.vector.* -import org.jbox2d.collision.shapes.* +import org.jbox2d.callbacks.* +import org.jbox2d.collision.* import org.jbox2d.dynamics.* +import org.jbox2d.dynamics.contacts.* suspend fun main() = Korge(quality = GameWindow.Quality.PERFORMANCE, title = "My Awesome Box2D Game!") { - val admob = AdmobCreate(testing = true) - - println("STARTED!") - - addUpdatable { - //println("FRAME!") - } - - launchImmediately { - try { - admob.bannerPrepareAndShow(Admob.Config("ca-app-pub-xxx/xxx")) - } catch (e: Throwable) { - e.printStackTrace() - } - } - - views.clearColor = Colors.DARKGREEN - solidRect(300, 200, Colors.DARKCYAN) - sgraphics { - fill(Colors.DARKCYAN) { - rect(-1, -1, 3, 2) - } - fill(Colors.AQUAMARINE) { - circle(0, 0, 1) - } - fill(Colors.AQUAMARINE) { - circle(1, 0, 1) - } - position(100, 100) - }.scale(100, 100).interactive() worldView { position(400, 400).scale(20) - createBody { setPosition(0, -10) }.fixture { shape = BoxShape(100, 20) density = 0f - }.setViewWithContainer(solidRect(100, 20, Colors.RED).position(-50, -10).interactive()) + }.setView(solidRect(100, 20, Colors.RED).position(-50, -10)) - // Dynamic Body - createBody { + val ball = createBody { type = BodyType.DYNAMIC - setPosition(0, 7) + setPosition(0, 0) }.fixture { - shape = BoxShape(2f, 2f) - density = 0.5f - friction = 0.2f - }.setView(solidRect(2f, 2f, Colors.GREEN).anchor(.5, .5).interactive()) + shape = BoxShape(4f, 4f) + density = 985f + friction = 0f + userData = "ball" + }.setView(container { + // [...] + }) - createBody { + val enemy = createBody { type = BodyType.DYNAMIC - setPosition(0.75, 13) + setPosition(5, 0) }.fixture { - shape = BoxShape(2f, 2f) - density = 1f - friction = 0.2f - }.setView(sgraphics { - fill(Colors.BLUE) { - rect(-1f, -1f, 2f, 2f) - } - }.interactive()) - - createBody { - type = BodyType.DYNAMIC - setPosition(0.5, 15) - }.fixture { - shape = CircleShape().apply { m_radius = 2f } - density = 22f - friction = 3f - }.setView(sgraphics { - fillStroke(Context2d.Color(Colors.BLUE), Context2d.Color(Colors.RED), Context2d.StrokeInfo(thickness = 0.3)) { - circle(0, 0, 2) - //rect(0, 0, 400, 20) - } - fill(Colors.DARKCYAN) { - circle(1, 1, 0.2) - } - hitTestUsingShapes = true - }.interactive()) + shape = BoxShape(10, 20) + }.setView(container { + image(resourcesVfs["korge-ui.png"].readBitmap()) + .size(4f, 4f) + .position(-2f, -2f) + }) + }.apply { + world.setContactListener(contactListener) } - image(resourcesVfs["korge.png"].readBitmap()) } -fun T.interactive(): T = this.apply { - alpha = 0.5 - onOver { alpha = 1.0 } - onOut { alpha = 0.5 } +val contactListener = object : ContactListener { + override fun beginContact(contact: Contact) { + println("beginContact") + } + + override fun endContact(contact: Contact) { + println("endContact") + } + + override fun postSolve(contact: Contact, impulse: ContactImpulse) { + println("postSolve") + } + + override fun preSolve(contact: Contact, oldManifold: Manifold) { + println("preSolve") + } } diff --git a/sample-lipsync/src/commonMain/resources/simple.voice.mp3 b/sample-lipsync/src/commonMain/resources/simple.voice.mp3 deleted file mode 100644 index 26d4e20e5917199b49a5c318fdc77326562f9f88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40161 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 diff --git a/sample-tic-tac-toe-swf/src/commonMain/kotlin/main.kt b/sample-tic-tac-toe-swf/src/commonMain/kotlin/main.kt index 332fc77..ea72bb0 100644 --- a/sample-tic-tac-toe-swf/src/commonMain/kotlin/main.kt +++ b/sample-tic-tac-toe-swf/src/commonMain/kotlin/main.kt @@ -13,7 +13,8 @@ import com.soywiz.korio.lang.* import com.soywiz.korma.geom.* import com.soywiz.korma.geom.ds.* -suspend fun main() = Korge(Korge.Config(module = TicTacToeModule, debug = true)) +//suspend fun main() = Korge(Korge.Config(module = TicTacToeModule, debug = true)) +suspend fun main() = Korge(Korge.Config(module = TicTacToeModule)) object TicTacToeModule : Module() { override val mainScene = TicTacToeMainScene::class diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/DefaultUISkin.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/DefaultUISkin.kt deleted file mode 100644 index c9e24bf..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/DefaultUISkin.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.kds.* -import com.soywiz.korge.html.* -import com.soywiz.korge.scene.* -import com.soywiz.korim.bitmap.* -import com.soywiz.korim.color.* -import com.soywiz.korim.font.* -import com.soywiz.korim.format.* -import com.soywiz.korio.util.* -import com.soywiz.korio.util.encoding.* - -val DEFAULT_UI_SKIN_IMG by lazy { - PNG.decode( - "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAG/klEQVR42uzXNVAkQRTG8beOu82SXnzu7u7uZtm5++HuLrmdu1uEW34Z5LjLuzdTNLXV18XG29Nf1a8g5F9NN6x9+dL1IJiT7J60hLiJE3xrfaSDtJBX5A0ZAcHM0h8aGi7qN/H5q1kED8AekklmgFz7S+6Ql8DNTP30CAj71fmrB8BGUsltkHuZ5D4ZBzYT9tNDYOp+Qv1qdmAzx+GDR+MdAmbuV/1qVqJvv+jwT5w8AhWVhfD562v48euDT3n34TmUVxYaDYLdnmyG6fpPnjoKldXF8PX7W/j155NP+fDpJVRWFekNwv7u7k6v/UHBLoiMDoRYLQTi3L4lVgs2fnZqmO781egjgJO0E2ROnriATU0tODg4KAW95djRs6yP6SBOUf+pExextaUNR0ZGpKC3HD96Tti/bcsBXTtBZvfOw3jy5Bk8f/78lAsXLuCNGzcwISEBs7KyMC8vD/Pz831CwtMkPHzwNOtjOogTQD0Axwh6amxsxoGBAanU1tTrbbzjov6W5jYcHh6WSn19k7CfLsExgp5OnTpjXHjCLr5x6QsKCnxWQkKy3sY7DqAegGcEmbLSKuzr65NOd3cPJidl8RfgOd9fXlat/9cgnb6+fkxJzv6vny7BM4LM4UMn8OLFi1MeP36MhYWFUrh86Qb/ADwHk89KFoDHli9fAhMTE9JBnIBZs2cCt/l8/8pVywARpQOAMHvubK/9AYEusFgsBk3TICYmBqxWqxTc7hhBv3oA4sBjsXGx+oWRUkRkJHDT+H5NiwNElFJ0dJTXfofDZlz+sLAw4/LT99IIDAoQ9KsHwAUes9msMD4+LiWr1QLcnHy/3W6X9gG0Wq1e+9lfy/j4eP2rVPSz5fvVA8CNflGk5m2IKDVv0y9KeHg4uFz/2LtjHYRhIAbDiAwMff/HzQWlYm9Yz98vRWVlwNi+a/vZn9sdRAvA0w/A9//Z/31tefAgAHPOtqdqcgAHAnBd1/63bHkgAsQ6gLXqRAC62n8CwAFUeAQ4E4AxBgHoBwdAAI5KwNYHsQ5gn+wO4HXWAQQJAN4ycJADWMUBINkB6AA4AOSWgHMSAA4AsQ4gfgyoA4BFIA6AAMAUgACIALAIZArCASRAAOrQAVgEGmO0PeAARAARADqAwAhQIgCi9wBsAhIABO8B6AB0ALAJaAqgA4BNQCWgCJADAeAAanEA4ACUgDoAGAOKACJADASg0m8GWrmLQASAANR9dTuwCAC3A4sAIgBsAhIAAhCFKYAxoA4A9gCMAXUAsAcgAogASRAAtwOLADAFyI0AngoMLwYRATgAGAOKABwAjAFNAQhACF4O6vXgIgCMAUNfD74PB4BIAbAItMI7AAIgApQHgogAEAESBWDdVxEASsDEDuCv5wEQgC+7ZrElRQxG4fs+vAGHJe7usGIJS3SF2xp3d3sH3N2hxqddS1NCyN/UoiaEU2wrk3vON9Kar+QmLaYAtCOOk5wlsP7+XOWvXgVoi8nfBWAjkyiKtDwBGGOqNwFD2Z+xUMsVQBAwJPn+dBttZ/8k+aXwNwVQQia+H2j32j+OY7iujyAIIaUk+9u2rV350Tbo2g4cQZ6/5/raFkCtWlP4mwJ4h0yajY52J4DtuIiTGI7tQsoL2d/6OaDd7N9qd5HECUqjlVz//v5hbZf/T568UPibAriHTEqjNdi2q8nM9+fkZwFD4DO0Wzak3JP937z+gGqlps0bf+12F74XoNVq48d3K9f/7ZtP+PHD0m72J6ebN+4p/E0B3BQMI5PBgRK6XaewS/4oiuD1DvoOnfi9pX+j3oGUEXJX+T+4/wylUgVxXDx3GjMLw16Jl8s1OK6HdruDjx8+/7f/yePnYf3s12bmt6x+cvqXv8mkiZOXCLjMzBnz+KLFy/iy5av48hXFgsZMYycHlRs55/mvXbuOb9y0jW/fsZvv2LmnSNCYaezkkOs/a8aSJQIuc/7cFf79+0/ueR5njBUKGjONnRxUbuQMkzElcFDAxwkHjf+YUAkcFPBxguRPMd8D2Co4BP1zOHXNxPgbf1MAiWCDYLHgB/QLOS0RrE9d0xh/428KIJvbggmC1enf/YIIxUsk6E8dVqdOt5Cf3+3PAQEAAAQAIPB/sx/Ug179/QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBsWW/M0jYx8rEYAAAAASUVORK5CYII=".fromBase64() - ).toBMP32() -} - -val DefaultUISkin by lazy { - UISkin( - normal = DEFAULT_UI_SKIN_IMG.sliceWithSize(0, 0, 64, 64), - hover = DEFAULT_UI_SKIN_IMG.sliceWithSize(64, 0, 64, 64), - down = DEFAULT_UI_SKIN_IMG.sliceWithSize(127, 0, 64, 64), - font = Html.FontFace.Bitmap(getSyncDebugBmpFontOnce()) - ) -} - -private class SyncOnce { - var value: T? = null - - operator fun invoke(callback: () -> T): T { - if (value == null) { - value = callback() - } - return value!! - } -} - - -private var bmpFontOnce2 = SyncOnce() - -private fun getSyncDebugBmpFontOnce() = bmpFontOnce2 { - val tex = PNG.decode(DebugBitmapFont.DEBUG_FONT_BYTES).toBMP32().premultiplied().slice() - val fntAdvance = 7 - val fntWidth = 8 - val fntHeight = 8 - - val fntBlockX = 2 - val fntBlockY = 2 - val fntBlockWidth = 12 - val fntBlockHeight = 12 - - BitmapFont(tex.bmp, fntHeight, fntHeight, fntHeight, (0 until 256).associate { - val x = it % 16 - val y = it / 16 - it to BitmapFont.Glyph( - it, - tex.sliceWithSize(x * fntBlockWidth + fntBlockX, y * fntBlockHeight + fntBlockY, fntWidth, fntHeight), - 0, - 0, - fntAdvance - ) - }.toIntMap(), IntMap()) -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIButton.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIButton.kt deleted file mode 100644 index 627dde2..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIButton.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.korge.html.* -import com.soywiz.korge.input.* -import com.soywiz.korge.render.* -import com.soywiz.korge.view.* -import com.soywiz.korim.color.* -import com.soywiz.korma.geom.* -import kotlin.properties.* - -inline fun Container.uiButton( - width: Number = 128, - height: Number = 64, - label: String = "Button", - skin: UISkin = defaultUISkin, - block: UIButton.() -> Unit = {} -): UIButton = UIButton(width.toDouble(), height.toDouble(), label, skin).also { addChild(it) }.apply(block) - -open class UIButton( - width: Double = 128.0, - height: Double = 64.0, - label: String = "Button", - skin: UISkin = DefaultUISkin -) : UIView(width, height) { - var forcePressed by uiObservable(false) { updateState() } - var skin: UISkin by uiObservable(skin) { updateState() } - var label by uiObservable(label) { updateState() } - private val rect = ninePatch(skin.normal, width, height, 16.0 / 64.0, 16.0 / 64.0, (64.0 - 16.0) / 64.0, (64.0 - 16.0) / 64.0) {} - private val textShadow = text(label).also { it.position(1, 1) } - private val text = text(label) - private var bover by uiObservable(false) { updateState() } - private var bpressing by uiObservable(false) { updateState() } - - // @TODO: Make mouseEnabled open - //override var mouseEnabled = uiObservable(true) { updateState() } - - fun simulateHover() { - bover = true - } - - fun simulateOut() { - bover = false - } - - fun simulatePressing(value: Boolean) { - bpressing = value - } - - fun simulateDown() { - bpressing = true - } - - fun simulateUp() { - bpressing = false - } - - init { - mouse { - onOver { - simulateHover() - } - onOut { - simulateOut() - } - onDown { - simulateDown() - } - onUpAnywhere { - simulateUp() - } - } - updateState() - } - - private fun updateState() { - when { - bpressing || forcePressed -> { - rect.tex = skin.down - } - bover -> { - rect.tex = skin.hover - } - else -> { - rect.tex = skin.normal - } - } - text.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_CENTER, color = Colors.WHITE) - text.setTextBounds(Rectangle(0, 0, width, height)) - text.setText(label) - textShadow.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_CENTER, color = Colors.BLACK.withA(64)) - textShadow.setTextBounds(Rectangle(0, 0, width, height)) - textShadow.setText(label) - } - - override fun updatedSize() { - super.updatedSize() - rect.width = width - rect.height = height - updateState() - } - - override fun renderInternal(ctx: RenderContext) { - //alpha = if (mouseEnabled) 1.0 else 0.5 - super.renderInternal(ctx) - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UICheckBox.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UICheckBox.kt deleted file mode 100644 index c403a11..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UICheckBox.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.korge.html.* -import com.soywiz.korge.input.* -import com.soywiz.korge.view.* -import com.soywiz.korim.color.* -import com.soywiz.korma.geom.* -import kotlin.properties.* - -inline fun Container.uiCheckBox( - checked: Boolean? = false, - width: Number = 96.0, - height: Number = 32.0, - label: String = "CheckBox", - skin: UISkin = defaultUISkin, - block: UICheckBox.() -> Unit = {} -): UICheckBox = UICheckBox(checked, width.toDouble(), height.toDouble(), label, skin).also { addChild(it) }.apply(block) - -open class UICheckBox( - checked: Boolean? = false, - width: Double = 96.0, - height: Double = 32.0, - label: String = "CheckBox", - private val skin: UISkin = DefaultUISkin -) : UIView(width, height) { - var checked by uiObservable(checked) { onPropsUpdate() } - var label by uiObservable(label) { onPropsUpdate() } - - private val area = solidRect(16, 16, Colors.TRANSPARENT_BLACK) - //private val box = solidRect(16, 16, Colors.DARKGREY) - private val box = uiButton(16, 16, skin = skin).also { it.mouseEnabled = false } - private val text = text(label) - - init { - onClick { - this@UICheckBox.checked = this@UICheckBox.checked != true - onPropsUpdate() - } - onPropsUpdate() - } - - protected fun onPropsUpdate() { - println("checked: $checked") - area.position(0, 0).size(width, height) - box.position(0, 0).size(height, height) - .also { - it.forcePressed = true - if (checked == true) { - it.label = "X" - } else { - it.label = "" - } - } - text.position(height + 8.0, 0) - .also { it.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_LEFT) } - .also { it.setTextBounds(Rectangle(0, 0, width - height, height)) } - .setText(label) - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIComboBox.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIComboBox.kt deleted file mode 100644 index d245ad5..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIComboBox.kt +++ /dev/null @@ -1,95 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.korge.input.* -import com.soywiz.korge.view.* -import com.soywiz.korim.color.* -import com.soywiz.korio.async.* - -inline fun Container.uiComboBox( - width: Number = 192.0, - height: Number = 32.0, - selectedIndex: Int = 0, - items: List, - skin: UISkin = defaultUISkin, - block: UIComboBox.() -> Unit = {} -) = UIComboBox(width.toDouble(), height.toDouble(), selectedIndex, items, skin).also { addChild(it) }.also(block) - -open class UIComboBox( - width: Double = 192.0, - height: Double = 32.0, - selectedIndex: Int = 0, - items: List, - private val skin: UISkin = DefaultUISkin -) : UIView(width, height) { - - val onUpdatedSelection = Signal>() - - var selectedIndex by uiObservable(selectedIndex) { updatedSelection() } - var selectedItem: T? - set(value) = run { selectedIndex = items.indexOf(value) } - get() = items.getOrNull(selectedIndex) - var items: List by uiObservable(items) { updatedItems() } - - val itemHeight get() = 32 - private val buttonSize get() = height - private val itemsView = uiScrollableArea(verticalScroll = true, horizontalScroll = false, skin = skin, config = { visible = false }) { } - private val selectedButton = uiButton(16, 16, "", skin = skin).also { it.mouseEnabled = false } - private val dropButton = uiButton(16, 16, "+", skin = skin).also { it.mouseEnabled = false } - private val invisibleRect = solidRect(16, 16, Colors.TRANSPARENT_BLACK) - private var showItems = false - - init { - updatedItems() - invisibleRect.onOver { - selectedButton.simulateHover() - dropButton.simulateHover() - } - invisibleRect.onOut { - selectedButton.simulateOut() - dropButton.simulateOut() - } - invisibleRect.onClick { - showItems = !showItems - updatedSize() - } - } - - override fun updatedSize() { - super.updatedSize() - itemsView.visible = showItems - itemsView.size(width, 196).position(0, height) - selectedButton.simulatePressing(showItems) - dropButton.simulatePressing(showItems) - dropButton.label = if (showItems) "-" else "+" - invisibleRect.size(width, height) - selectedButton.position(0, 0).size(width - buttonSize, height) - selectedButton.label = selectedItem?.toString() ?: "" - //println("selectedIndex: $selectedIndex, selectedItem: $selectedItem") - dropButton.position(width - buttonSize, 0).size(buttonSize, height) - } - - protected fun updatedSelection() { - updatedSize() - for (n in items.indices) { - val button = itemsView.container.children[n] as? UIButton? ?: continue - button.forcePressed = selectedIndex == n - } - onUpdatedSelection(this) - } - - protected fun updatedItems() { - itemsView.container.removeChildren() - for ((index, item) in items.withIndex()) { - val button = itemsView.container.uiButton(width - 32, itemHeight, label = item.toString(), skin = skin) { - position(0, index * itemHeight) - onClick { - showItems = false - selectedIndex = index - updatedSize() - } - } - } - itemsView.contentHeight = ((items.size) * itemHeight).toDouble() - updatedSelection() - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIObservable.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIObservable.kt deleted file mode 100644 index d080062..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIObservable.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.soywiz.korge.newui - -import kotlin.reflect.* - -inline fun uiObservable(value: T, noinline observe: () -> Unit) = UIObservable(value, observe) - -class UIObservable(val initial: T, val observe: () -> Unit) { - var currentValue = initial - - operator fun getValue(obj: Any, prop: KProperty<*>): T { - return currentValue - } - - operator fun setValue(obj: Any, prop: KProperty<*>, value: T) { - currentValue = value - observe() - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIProgressBar.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIProgressBar.kt deleted file mode 100644 index 5b50d78..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIProgressBar.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.korge.view.* - -inline fun Container.uiProgressBar( - width: Number = 256.0, - height: Number = 24.0, - current: Number = 0.0, - maximum: Number = 1.0, - skin: UISkin = defaultUISkin, - block: UIProgressBar.() -> Unit = {} -): UIProgressBar = UIProgressBar(width.toDouble(), height.toDouble(), current.toDouble(), maximum.toDouble(), skin).also { addChild(it) }.also(block) - -open class UIProgressBar( - width: Double = 256.0, - height: Double = 24.0, - current: Double = 0.0, - maximum: Double = 1.0, - skin: UISkin = DefaultUISkin -) : UIView(width, height) { - var current: Double by uiObservable(current) { updatedSize() } - var maximum: Double by uiObservable(maximum) { updatedSize() } - override var ratio: Double - set(value) = run { current = value * maximum } - get() = current / maximum - - private val bg = solidRect(width, height, skin.backColor) - private val progress = uiButton(width, height, "", skin = skin).also { mouseEnabled = false } - - init { - updatedSize() - } - - override fun updatedSize() { - bg.size(width, height) - progress.forcePressed = true - progress.size(width * ratio, height) - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollBar.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollBar.kt deleted file mode 100644 index ac78adf..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollBar.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.kmem.* -import com.soywiz.korge.input.* -import com.soywiz.korge.view.* -import com.soywiz.korio.async.* -import com.soywiz.korma.geom.* -import kotlin.math.* -import kotlin.properties.* - -inline fun Container.uiScrollBar( - width: Number, - height: Number, - current: Number = 0.0, - pageSize: Number = 1.0, - totalSize: Number = 10.0, - buttonSize: Number = 32.0, - direction: UIScrollBar.Direction = if (width.toDouble() > height.toDouble()) UIScrollBar.Direction.Horizontal else UIScrollBar.Direction.Vertical, - stepSize: Double = pageSize.toDouble() / 10.0, - skin: UISkin = defaultUISkin, - block: UIScrollBar.() -> Unit = {} -): UIScrollBar = UIScrollBar(width.toDouble(), height.toDouble(), current.toDouble(), pageSize.toDouble(), totalSize.toDouble(), buttonSize.toDouble(), direction, stepSize, skin).also { addChild(it) }.apply(block) - -open class UIScrollBar( - width: Double, - height: Double, - current: Double, - pageSize: Double, - totalSize: Double, - buttonSize: Double = 32.0, - direction: Direction = if (width > height) Direction.Horizontal else Direction.Vertical, - var stepSize: Double = pageSize / 10.0, - skin: UISkin = DefaultUISkin -) : UIView() { - val onChange = Signal() - enum class Direction { Vertical, Horizontal } - var current by uiObservable(current) { updatedPos() } - var pageSize by uiObservable(pageSize) { updatedPos() } - var totalSize by uiObservable(totalSize) { updatedPos() } - var direction by uiObservable(direction) { reshape() } - val isHorizontal get() = direction == Direction.Horizontal - val isVertical get() = direction == Direction.Vertical - override var ratio: Double - set(value) = run { current = value.clamp01() * (totalSize - pageSize) } - get() = (current / (totalSize - pageSize)).clamp(0.0, 1.0) - override var width: Double by uiObservable(width) { reshape() } - override var height: Double by uiObservable(height) { reshape() } - var buttonSize by uiObservable(buttonSize) { reshape() } - val buttonWidth get() = if (isHorizontal) buttonSize else width - val buttonHeight get() = if (isHorizontal) height else buttonSize - val clientWidth get() = if (isHorizontal) width - buttonWidth * 2 else width - val clientHeight get() = if (isHorizontal) height else height - buttonHeight * 2 - - protected val background = solidRect(100, 100, skin.backColor) - protected val lessButton = uiButton(16, 16, "-", skin = skin) - protected val moreButton = uiButton(16, 16, "+", skin = skin) - protected val caretButton = uiButton(16, 16, "", skin = skin) - - protected val views get() = stage?.views - - init { - reshape() - - var slx: Double = 0.0 - var sly: Double = 0.0 - var iratio: Double = 0.0 - var sratio: Double = 0.0 - val tempP = Point() - - lessButton.onDown { - deltaCurrent(-stepSize) - reshape() - } - moreButton.onDown { - deltaCurrent(+stepSize) - reshape() - } - background.onClick { - val pos = if (isHorizontal) caretButton.localMouseX(views!!) else caretButton.localMouseY(views!!) - deltaCurrent(this.pageSize * pos.sign) - } - caretButton.onMouseDrag { - val lmouse = background.localMouseXY(views, tempP) - val lx = lmouse.x - val ly = lmouse.y - val cratio = if (isHorizontal) lmouse.x / background.width else lmouse.y / background.height - if (it.start) { - slx = lx - sly = ly - iratio = ratio - sratio = cratio - } - val dratio = cratio - sratio - ratio = iratio + dratio - reshape() - } - } - - private fun deltaCurrent(value: Double) { - //println("deltaCurrent: $value") - current = (current + value).clamp(0.0, totalSize - pageSize) - } - - private fun reshape() { - if (isHorizontal) { - background.position(buttonWidth, 0).size(clientWidth, clientHeight) - lessButton.position(0, 0).size(buttonWidth, buttonHeight) - moreButton.position(width - buttonWidth, 0).size(buttonWidth, buttonHeight) - val caretWidth = (clientWidth * (pageSize / totalSize)).clamp(4.0, clientWidth) - caretButton.position(buttonWidth + (clientWidth - caretWidth) * ratio, 0).size(caretWidth, buttonHeight) - } else { - background.position(0, buttonHeight).size(clientWidth, clientHeight) - lessButton.position(0, 0).size(buttonWidth, buttonHeight) - moreButton.position(0, height - buttonHeight).size(buttonWidth, buttonHeight) - val caretHeight = (clientHeight * (pageSize / totalSize)).clamp(4.0, clientHeight) - caretButton.position(0, buttonHeight + (clientHeight - caretHeight) * ratio).size(buttonWidth, caretHeight) - } - } - - private fun updatedPos() { - reshape() - onChange(this) - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollableArea.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollableArea.kt deleted file mode 100644 index cfc99a1..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIScrollableArea.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.korge.view.* - -inline fun Container.uiScrollableArea( - width: Number = 256.0, - height: Number = 256.0, - contentWidth: Number = 512.0, - contentHeight: Number = 512.0, - buttonSize: Number = 32.0, - verticalScroll: Boolean = true, - horizontalScroll: Boolean = true, - skin: UISkin = defaultUISkin, - config: UIScrollableArea.() -> Unit = {}, - block: Container.() -> Unit = {} -): UIScrollableArea = UIScrollableArea( - width.toDouble(), height.toDouble(), contentWidth.toDouble(), contentHeight.toDouble(), buttonSize.toDouble(), verticalScroll, horizontalScroll, skin -).also { addChild(it) }.also(config).also { block(it.container) } - -// @TODO: Optimize this! -// @TODO: Add an actualContainer = this inside Container -open class UIScrollableArea( - width: Double = 256.0, - height: Double = 256.0, - contentWidth: Double = 512.0, - contentHeight: Double = 512.0, - buttonSize: Double = 32.0, - verticalScroll: Boolean = true, - horizontalScroll: Boolean = true, - skin: UISkin = DefaultUISkin -) : UIView(width, height) { - var buttonSize by uiObservable(buttonSize) { updatedSize() } - - var contentWidth by uiObservable(contentWidth) { updatedSize() } - var contentHeight by uiObservable(contentHeight) { updatedSize() } - - var verticalScroll by uiObservable(verticalScroll) { updatedSize() } - var horizontalScroll by uiObservable(horizontalScroll) { updatedSize() } - - val clientWidth get() = if (verticalScroll) width - buttonSize else width - val clientHeight get() = if (horizontalScroll) height - buttonSize else height - - val clipContainer = clipContainer(clientWidth, clientHeight) - val container = clipContainer.fixedSizeContainer(contentWidth, contentHeight) - val horScroll = uiScrollBar(width, buttonSize, skin = skin).also { it.onChange { moved() } } - val verScroll = uiScrollBar(buttonSize, height, skin = skin).also { it.onChange { moved() } } - - init { - updatedSize() - } - - override fun updatedSize() { - super.updatedSize() - - horScroll.totalSize = contentWidth - horScroll.pageSize = clientWidth - horScroll.stepSize = clientWidth / 4 - - verScroll.totalSize = contentHeight - verScroll.pageSize = clientHeight - verScroll.stepSize = clientHeight / 4 - - clipContainer.size(clientWidth, clientHeight) - container.size(contentWidth, contentHeight) - - horScroll.size(clientWidth, buttonSize).position(0, height - buttonSize).also { it.visible = horizontalScroll } - verScroll.size(buttonSize, clientHeight).position(width - buttonSize, 0).also { it.visible = verticalScroll } - } - - protected fun moved() { - //println("" + verScroll.current + " :: " + verScroll.totalSize + " :: " + verScroll.pageSize + " :: " + verScroll.stepSize) - container.x = -horScroll.current - container.y = -verScroll.current - } -} diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UISkin.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UISkin.kt deleted file mode 100644 index a703a71..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UISkin.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.kds.* -import com.soywiz.korge.html.* -import com.soywiz.korge.view.* -import com.soywiz.korim.bitmap.* -import com.soywiz.korim.color.* - -@PublishedApi -internal var View.internalDefaultUISkin: UISkin? by extraProperty("defaultUiSkin") { null } -var View.defaultUISkin: UISkin - set(value) = run { internalDefaultUISkin = value } - get() = internalDefaultUISkin ?: parent?.defaultUISkin ?: DefaultUISkin - -fun Container.uiSkin(skin: UISkin, block: Container.() -> Unit) { - defaultUISkin = skin - block() -} - -data class UISkin( - val normal: BmpSlice, - val hover: BmpSlice, - val down: BmpSlice, - val backColor: RGBA = Colors.DARKGREY, - val font: Html.FontFace = Html.FontFace.Named("Arial") -) diff --git a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIView.kt b/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIView.kt deleted file mode 100644 index 544f769..0000000 --- a/sample-ui/src/commonMain/kotlin/com/soywiz/korge/newui/UIView.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.soywiz.korge.newui - -import com.soywiz.kds.* -import com.soywiz.korge.component.* -import com.soywiz.korge.input.* -import com.soywiz.korge.render.* -import com.soywiz.korge.view.* -import kotlin.properties.* - -open class UIView( - width: Double = 90.0, - height: Double = 32.0 -) : Container() { - override var width: Double by uiObservable(width) { updatedSize() } - override var height: Double by uiObservable(height) { updatedSize() } - - open var uiEnabled by uiObservable(true) { updateEnabled() } - open var uiDisabled: Boolean - set(value) = run { uiEnabled = !value } - get() = !uiEnabled - - fun enable(set: Boolean = true) = run { uiEnabled = set } - fun disable() = run { uiEnabled = false } - - protected open fun updatedSize() { - } - - protected open fun updateEnabled() { - mouseEnabled = uiEnabled - // @TODO: Shouldn't change alpha - alpha = if (uiEnabled) 1.0 else 0.7 - } - - override fun renderInternal(ctx: RenderContext) { - registerUISupportOnce() - super.renderInternal(ctx) - } - - private var registered = false - private fun registerUISupportOnce() { - if (registered) return - val stage = stage ?: return - registered = true - if (stage.getExtra("uiSupport") == true) return - stage.setExtra("uiSupport", true) - stage.keys { - onKeyDown { - - } - } - stage?.getOrCreateComponent { stage -> - object : UpdateComponentWithViews { - override val view: View = stage - override fun update(views: Views, ms: Double) { - } - } - } - } - -}