Add click handlers

This commit is contained in:
Alexander Nozik 2023-11-24 10:02:25 +03:00
parent e6bdb67262
commit 80284a99ef
5 changed files with 63 additions and 28 deletions

View File

@ -0,0 +1,52 @@
package space.kscience.visionforge
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.MutableMeta
@Serializable
@SerialName("control")
public abstract class VisionControlEvent : VisionEvent, MetaRepr {
public abstract val meta: Meta
override fun toMeta(): Meta = meta
}
public interface ControlVision : Vision {
public val controlEventFlow: Flow<VisionControlEvent>
public fun dispatchControlEvent(event: VisionControlEvent)
override fun receiveEvent(event: VisionEvent) {
if (event is VisionControlEvent) {
dispatchControlEvent(event)
} else super.receiveEvent(event)
}
}
@Serializable
@SerialName("control.click")
public class VisionClickEvent(override val meta: Meta) : VisionControlEvent()
public interface ClickControl : ControlVision {
public fun click(builder: MutableMeta.() -> Unit = {}) {
dispatchControlEvent(VisionClickEvent(Meta(builder)))
}
public fun onClick(scope: CoroutineScope, block: suspend VisionClickEvent.() -> Unit): Job {
return controlEventFlow.filterIsInstance<VisionClickEvent>().onEach(block).launchIn(scope)
}
public companion object {
}
}

View File

@ -4,7 +4,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.context.logger
import space.kscience.dataforge.context.warn
import space.kscience.dataforge.meta.asValue import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.Described
@ -37,7 +38,7 @@ public interface Vision : Described {
/** /**
* Update this vision using a dif represented by [VisionChange]. * Update this vision using a dif represented by [VisionChange].
*/ */
public fun receiveChange(change: VisionChange) { public fun update(change: VisionChange) {
if (change.children?.isNotEmpty() == true) { if (change.children?.isNotEmpty() == true) {
error("Vision is not a group") error("Vision is not a group")
} }
@ -46,18 +47,12 @@ public interface Vision : Described {
} }
} }
public fun onMetaEvent(meta: Meta){
//Do nothing by default
}
/** /**
* Receive and process a generic [VisionEvent]. * Receive and process a generic [VisionEvent].
*/ */
public fun receiveEvent(event: VisionEvent) { public fun receiveEvent(event: VisionEvent) {
when (event) { if(event is VisionChange) update(event)
is VisionChange -> receiveChange(event) else manager?.logger?.warn { "Undispatched event: $event" }
is VisionMetaEvent -> onMetaEvent(event.meta)
}
} }
override val descriptor: MetaDescriptor? override val descriptor: MetaDescriptor?

View File

@ -3,8 +3,6 @@ package space.kscience.visionforge
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
/** /**
@ -22,14 +20,4 @@ public sealed interface VisionEvent {
*/ */
@Serializable @Serializable
@SerialName("meta") @SerialName("meta")
public class VisionMetaEvent(public val meta: Meta) : VisionEvent public class VisionMetaEvent(public val meta: Meta) : VisionEvent
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
/**
* Set the payload to be sent to server on click
*/
public fun Vision.onClickPayload(payloadBuilder: MutableMeta.() -> Unit) {
properties[VisionEvent.CLICK_EVENT_KEY] = Meta(payloadBuilder)
}

View File

@ -17,12 +17,12 @@ import space.kscience.visionforge.Vision.Companion.STYLE_KEY
public interface VisionGroup : Vision { public interface VisionGroup : Vision {
public val children: VisionChildren public val children: VisionChildren
override fun receiveChange(change: VisionChange) { override fun update(change: VisionChange) {
change.children?.forEach { (name, change) -> change.children?.forEach { (name, change) ->
if (change.vision != null || change.vision == NullVision) { if (change.vision != null || change.vision == NullVision) {
error("VisionGroup is read-only") error("VisionGroup is read-only")
} else { } else {
children.getChild(name)?.receiveChange(change) children.getChild(name)?.update(change)
} }
} }
change.properties?.let { change.properties?.let {
@ -37,12 +37,12 @@ public interface MutableVisionGroup : VisionGroup {
public fun createGroup(): MutableVisionGroup public fun createGroup(): MutableVisionGroup
override fun receiveChange(change: VisionChange) { override fun update(change: VisionChange) {
change.children?.forEach { (name, change) -> change.children?.forEach { (name, change) ->
when { when {
change.vision == NullVision -> children.setChild(name, null) change.vision == NullVision -> children.setChild(name, null)
change.vision != null -> children.setChild(name, change.vision) change.vision != null -> children.setChild(name, change.vision)
else -> children.getChild(name)?.receiveChange(change) else -> children.getChild(name)?.update(change)
} }
} }
change.properties?.let { change.properties?.let {

View File

@ -28,7 +28,7 @@ internal class VisionUpdateTest {
propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue())) propertyChanged("top".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue())) propertyChanged("origin".asName(), SolidMaterial.MATERIAL_COLOR_KEY, Meta("red".asValue()))
} }
targetVision.receiveChange(dif) targetVision.update(dif)
assertTrue { targetVision.children.getChild("top") is SolidGroup } assertTrue { targetVision.children.getChild("top") is SolidGroup }
assertEquals("red", (targetVision.children.getChild("origin") as Solid).color.string) // Should work assertEquals("red", (targetVision.children.getChild("origin") as Solid).color.string) // Should work
assertEquals( assertEquals(