Skip to content

Commit

Permalink
Do not scope to views.mouse.coroutineContext by default. Create new o…
Browse files Browse the repository at this point in the history
…nClickSuspend*/onMouseStuffSuspend* variants allowing suspending, while making the older ones non-suspending so we don't have problem with the coroutineContext Job scope

Unify QView and View mouse events
  • Loading branch information
soywiz committed Jul 18, 2024
1 parent 35b78d4 commit 4c15b8f
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 55 deletions.
13 changes: 6 additions & 7 deletions korge-sandbox/src/samples/MainAudioScene.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import korlibs.korge.view.*
class MainAudioScene : Scene() {
override suspend fun SContainer.sceneMain() {
uiVerticalStack(width = 640.0) {
println("coroutineContext=$coroutineContext")
uiButton(label = "Small MP3 Sound") { onClick { resourcesVfs["sounds/mp3.mp3"].readSound().play() } }
uiButton(label = "Small MP3 Music") { onClick { resourcesVfs["sounds/mp3.mp3"].readMusic().play() } }
uiButton(label = "Small WAV Sound") { onClick { resourcesVfs["sounds/wav.wav"].readSound().play() } }
uiButton(label = "Small WAV Music") { onClick { resourcesVfs["sounds/wav.wav"].readMusic().play() } }
uiButton(label = "Long MP3 Sound") { onClick { resourcesVfs["sounds/Snowland.mp3"].readSound().play() } }
uiButton(label = "Long MP3 Music") { onClick { resourcesVfs["sounds/Snowland.mp3"].readMusic().play() } }
uiButton(label = "Small MP3 Sound") { onClickSuspend { resourcesVfs["sounds/mp3.mp3"].readSound().play() } }
uiButton(label = "Small MP3 Music") { onClickSuspend { resourcesVfs["sounds/mp3.mp3"].readMusic().play() } }
uiButton(label = "Small WAV Sound") { onClickSuspend { resourcesVfs["sounds/wav.wav"].readSound().play() } }
uiButton(label = "Small WAV Music") { onClickSuspend { resourcesVfs["sounds/wav.wav"].readMusic().play() } }
uiButton(label = "Long MP3 Sound") { onClickSuspend { resourcesVfs["sounds/Snowland.mp3"].readSound().play() } }
uiButton(label = "Long MP3 Music") { onClickSuspend { resourcesVfs["sounds/Snowland.mp3"].readMusic().play() } }
//uiButton(label = "OGG Sound") { onClick { resourcesVfs["sounds/ogg.ogg"].readSound().play() } }
//uiButton(label = "OGG Music") { onClick { resourcesVfs["sounds/ogg.ogg"].readMusic().play() } }
}
Expand Down
2 changes: 1 addition & 1 deletion korge-sandbox/src/samples/MainEasing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class MainEasing : Scene() {
text("$easing", textSize = textSize).xy(0.0, textSize)
onOver { bg.color = Colors.BLACK.withAd(1.0) }
onOut { bg.color = Colors.BLACK.withAd(0.2) }
onClick {
onClickSuspend(coroutineContext) {
ballTween?.cancel()
ballTween = ball.tweenAsync(ball::x[64f, 64f + 512f], easing = easing)
}
Expand Down
6 changes: 3 additions & 3 deletions korge-sandbox/src/samples/MainScenes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class MainScenes : Scene() {
alpha = 0.7
onOver { alpha = 1.0 }
onOut { alpha = 0.7 }
onClick {
onClickSuspend {
sceneContainer.changeTo<MyScene2>()
}
}
Expand All @@ -48,7 +48,7 @@ class MainScenes : Scene() {
alpha = 0.7
onOver { alpha = 1.0 }
onOut { alpha = 0.7 }
onClick {
onClickSuspend {
sceneContainer.changeTo<MyScene2>()
}
}
Expand All @@ -64,7 +64,7 @@ class MainScenes : Scene() {

val blueSquare = solidRect(100, 100, Colors.BLUE) {
position(200, 200)
onClick {
onClickSuspend {
sceneContainer.changeTo<MyScene1>(MyDependency("From MyScene2"))
}
}
Expand Down
2 changes: 1 addition & 1 deletion korge-sandbox/src/samples/MainUI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class MainUI : Scene() {
}
uiButton(size = Size(256.0, 32.0)) {
text = "Close Window"
onClick {
onClickSuspend {
if (gameWindow.confirm("Are you sure to close the window?")) {
gameWindow.close()
}
Expand Down
2 changes: 1 addition & 1 deletion korge-sandbox/src/samples/pong/MenuScene.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class MenuScene() : Scene() {
var playButton = uiButton(size = Size(256.0, 32.0)) {
text = "Play"
position(sceneWidth / 2 - 128, sceneHeight / 2 - 64)
onClick {
onClickSuspend {
sceneContainer.changeTo<PlayScene>()
}
}
Expand Down
97 changes: 60 additions & 37 deletions korge/src/korlibs/korge/input/MouseEvents.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package korlibs.korge.input

import korlibs.datastructure.*
import korlibs.datastructure.iterators.*
import korlibs.event.*
import korlibs.image.bitmap.*
import korlibs.image.color.*
Expand All @@ -13,6 +14,8 @@ import korlibs.korge.view.*
import korlibs.math.geom.*
import korlibs.render.*
import korlibs.time.*
import kotlinx.coroutines.*
import kotlin.coroutines.*
import kotlin.math.*
import kotlin.native.concurrent.*
import kotlin.reflect.*
Expand Down Expand Up @@ -556,12 +559,26 @@ inline fun <T : View> T.mouse(callback: MouseEvents.() -> Unit): T {
}

@PublishedApi
internal inline fun <T : View?> T?.doMouseEvent(
internal inline fun <T : BView?> T?.doMouseEventSuspend(
prop: KProperty1<MouseEvents, Signal<MouseEvents>>,
noinline handler: suspend (MouseEvents) -> Unit
noinline handler: suspend (MouseEvents) -> Unit,
coroutineContext: CoroutineContext? = null,
): T? {
this?.mouse?.let { mouse ->
prop.get(mouse).add { launchImmediately(mouse.coroutineContext) { handler(it) } }
this?.bviewAll?.fastForEach {
it?.mouse?.let { mouse ->
prop.get(mouse).add { launchImmediately(coroutineContext ?: mouse.coroutineContext) { handler(it) } }
}
}
return this
}

@PublishedApi
internal inline fun <T : BView?> T?.doMouseEvent(
prop: KProperty1<MouseEvents, Signal<MouseEvents>>,
noinline handler: (MouseEvents) -> Unit,
): T? {
this?.bviewAll?.fastForEach {
it?.mouse?.let { mouse -> prop.get(mouse).add { handler(it) } }
}
return this
}
Expand All @@ -572,49 +589,55 @@ annotation class EventsDslMarker

// @TODO: onOut should happen before onOver (circumvented via onNextFrame)

inline fun <T : View> T.onOutOnOver(
inline fun <T : BView> T.onOutOnOver(
noinline out: @EventsDslMarker (MouseEvents) -> Unit,
noinline over: @EventsDslMarker (MouseEvents) -> Unit
): T {
var component: AutoCloseable? = null
var components: List<AutoCloseable> = emptyList()
onOut { events ->
component?.close()
component = null
components.fastForEach { it.close() }
components = emptyList()
out(events)
}
onOver { events -> component = onNextFrame { over(events) } }
onOver { events ->
components = bviewAll.map { it.onNextFrame { over(events) } }
}
return this
}

inline fun <T : View?> T.onClick(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::click, handler)

inline fun <T : View?> T.onOver(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::over, handler)

inline fun <T : View?> T.onOut(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::out, handler)

inline fun <T : View?> T.onDown(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::down, handler)

inline fun <T : View?> T.onDownFromOutside(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::downFromOutside, handler)

inline fun <T : View?> T.onUp(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::up, handler)

inline fun <T : View?> T.onUpOutside(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::upOutside, handler)

inline fun <T : View?> T.onUpAnywhere(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::upAnywhere, handler)

inline fun <T : View?> T.onMove(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::move, handler)
inline fun <T : BView?> T.onClickSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::click, handler, coroutineContext)
inline fun <T : BView?> T.onOverSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::over, handler, coroutineContext)
inline fun <T : BView?> T.onOutSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::out, handler, coroutineContext)
inline fun <T : BView?> T.onDownSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::down, handler, coroutineContext)
inline fun <T : BView?> T.onDownFromOutsideSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::downFromOutside, handler, coroutineContext)
inline fun <T : BView?> T.onUpSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::up, handler, coroutineContext)
inline fun <T : BView?> T.onUpOutsideSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::upOutside, handler, coroutineContext)
inline fun <T : BView?> T.onUpAnywhereSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::upAnywhere, handler, coroutineContext)
inline fun <T : BView?> T.onMoveSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::move, handler, coroutineContext)
inline fun <T : BView?> T.onScrollSuspend(coroutineContext: CoroutineContext?, noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::scroll, handler, coroutineContext)

suspend inline fun <T : BView?> T.onClickSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::click, handler, coroutineContext)
suspend inline fun <T : BView?> T.onOverSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::over, handler, coroutineContext)
suspend inline fun <T : BView?> T.onOutSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::out, handler, coroutineContext)
suspend inline fun <T : BView?> T.onDownSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::down, handler, coroutineContext)
suspend inline fun <T : BView?> T.onDownFromOutsideSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::downFromOutside, handler, coroutineContext)
suspend inline fun <T : BView?> T.onUpSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::up, handler, coroutineContext)
suspend inline fun <T : BView?> T.onUpOutsideSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::upOutside, handler, coroutineContext)
suspend inline fun <T : BView?> T.onUpAnywhereSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::upAnywhere, handler, coroutineContext)
suspend inline fun <T : BView?> T.onMoveSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::move, handler, coroutineContext)
suspend inline fun <T : BView?> T.onScrollSuspend(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = doMouseEventSuspend(MouseEvents::scroll, handler, coroutineContext)

inline fun <T : BView?> T.onClick(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::click, handler)
inline fun <T : BView?> T.onOver(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::over, handler)
inline fun <T : BView?> T.onOut(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::out, handler)
inline fun <T : BView?> T.onDown(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::down, handler)
inline fun <T : BView?> T.onDownFromOutside(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::downFromOutside, handler)
inline fun <T : BView?> T.onUp(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::up, handler)
inline fun <T : BView?> T.onUpOutside(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::upOutside, handler)
inline fun <T : BView?> T.onUpAnywhere(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::upAnywhere, handler)
inline fun <T : BView?> T.onMove(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::move, handler)
inline fun <T : BView?> T.onScroll(noinline handler: @EventsDslMarker (MouseEvents) -> Unit) = doMouseEvent(MouseEvents::scroll, handler)

inline fun <T : View?> T.onScroll(noinline handler: @EventsDslMarker suspend (MouseEvents) -> Unit) =
doMouseEvent(MouseEvents::scroll, handler)

fun ViewsContainer.installMouseDebugExtensionOnce() = MouseEvents.installDebugExtensionOnce(views)

Expand Down
4 changes: 2 additions & 2 deletions korge/src/korlibs/korge/ui/UIWindow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import korlibs.math.interpolation.*
import korlibs.render.*
import korlibs.time.*


@KorgeExperimental
inline fun Container.uiWindow(
title: String,
Expand Down Expand Up @@ -59,8 +58,9 @@ class UIWindow(title: String, size: Size = Size(256, 256)) : UIContainer(size) {
elevation = false
bgColorOut = MaterialColors.RED_600
bgColorOver = MaterialColors.RED_800
onClick { closeAnimated() }
onClickSuspend(null) { closeAnimated() }
}

var title: String by titleView::plainText
val container = uiScrollable(Size(width, height - titleHeight)).position(0.0, titleHeight).also {
it.backgroundColor = Colors["#161a1d"]
Expand Down
2 changes: 0 additions & 2 deletions korge/src/korlibs/korge/view/QView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package korlibs.korge.view

import korlibs.datastructure.iterators.*
import korlibs.image.color.*
import korlibs.korge.input.*
import korlibs.math.geom.*
import kotlin.reflect.*

Expand Down Expand Up @@ -54,7 +53,6 @@ class QView(val views: List<View>) : List<View> by views, BView {

fun QView.visible(value: Boolean) { visible = value }
fun QView.alpha(value: Double) { alpha = value }
fun QView.onClick(handler: @EventsDslMarker suspend (MouseEvents) -> Unit) = fastForEach { it.onClick(handler) }
inline fun <reified T : View> QView.castTo(): T? = firstOrNull as? T?

/** Indexer that allows to get a descendant marked with the name [name]. */
Expand Down
2 changes: 1 addition & 1 deletion korge/src@jvm/korlibs/korge/testing/testing_utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ inline fun korgeScreenshotTestV2(

viewsToAlign += uiButton("Accept change?") {
centerXOn(this@container)
onClick {
onClickSuspend {
val goldenFileNameWithExt =
context.makeGoldenFileNameWithExtension(testResult.goldenName)
if (testResult.newBitmap != null) {
Expand Down

0 comments on commit 4c15b8f

Please sign in to comment.