Skip to content

Commit

Permalink
States with the gui
Browse files Browse the repository at this point in the history
  • Loading branch information
ewoudje committed Feb 26, 2024
1 parent 14628d6 commit cd22121
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ object ContainerVerification {
override val parent: EGGContainerParent,
override val childId: Int
) : EGGFixedElement, EGGFillingElement {
override val attachment: EGGElementAttachment = EGGElementAttachment()

override fun visit(ctx: EGGContext) {
when (ctx.pass) {
is TestPass -> {
Expand Down
9 changes: 5 additions & 4 deletions src/commonMain/kotlin/com/ewoudje/eggui/EGGPass.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ewoudje.eggui

interface EGGPass {
data class Render(private val renderer: EGGRenderer) : EGGPass, EGGRenderer by renderer
data class BuildAssets(private val assetBuilder: EGGAssets): EGGPass, EGGAssets by assetBuilder
}
interface EGGPass
interface EGGInitPass: EGGPass

data class RenderPass(private val renderer: EGGRenderer) : EGGPass, EGGRenderer by renderer
data class BuildAssetsPass(private val assetBuilder: EGGAssets): EGGInitPass, EGGAssets by assetBuilder
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ import com.ewoudje.eggui.*
import com.ewoudje.eggui.frontend.EGGBuilderMarker

@EGGBuilderMarker
sealed interface EGGComponent
sealed interface EGGComponent{
val attachment: EGGComponentAttachment
}

sealed interface EGGComponentAttachment
open class EGGContainerAttachment(
var onEnter: (EGGPass) -> Boolean = {false},
var onExit: (EGGPass) -> Boolean = {false}
): EGGComponentAttachment

open class EGGElementAttachment(
var onVisit: (EGGPass) -> Boolean = {false}
): EGGComponentAttachment

sealed interface EGGChildComponent : EGGComponent {
val parent: EGGContainerParent
Expand All @@ -26,6 +38,8 @@ sealed interface EGGChildComponent : EGGComponent {
typealias EGGChildConstructor<T> = (EGGContainerParent, Int) -> T

sealed interface EGGElement : EGGChildComponent {
override val attachment: EGGElementAttachment

fun visit(context: EGGContext) {}
}

Expand All @@ -38,6 +52,8 @@ sealed interface EGGContainerParent : EGGComponent {
}

sealed interface EGGContainer : EGGChildComponent, EGGContainerParent {
override val attachment: EGGContainerAttachment

fun enter(context: EGGContext): EGGContext
fun exit(context: EGGContext) {}
}
Expand Down Expand Up @@ -67,6 +83,7 @@ interface EGGSingleContainer : EGGContainer {
}

class RootContainer : EGGContainerParent {
override val attachment = EGGContainerAttachment()
var child: EGGChildComponent? = null
var size = Size.EMPTY

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.ewoudje.eggui.frontend.ChildBuilder
import com.ewoudje.eggui.frontend.EGGBuilderMarker

class FixedContainer(override val parent: EGGContainerParent, override val childId: Int) : EGGSingleContainer {
override val attachment: EGGContainerAttachment = EGGContainerAttachment()
override var child: EGGChildComponent? = null
private set
private var childSize = Size.FILL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class HorizontalContainer(
override val parent: EGGContainerParent,
override val childId: Int
) : EGGMultipleContainer {
override val attachment: EGGContainerAttachment = EGGContainerAttachment()
override val children = mutableListOf<EGGChildComponent>()
private val sizes = mutableListOf<Size>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class SquareContainer(
override val parent: EGGContainerParent,
override val childId: Int
) : EGGSingleContainer {
override val attachment: EGGContainerAttachment = EGGContainerAttachment()

override var child: EGGChildComponent? = null
private set
Expand All @@ -21,9 +22,9 @@ class SquareContainer(
}

override fun getChildSize(): Size = childSize
override fun <T : EGGChildComponent> setChild(child: EGGChildConstructor<T>): T {
return child(this, 0).also { this.child = it }
}
override fun <T : EGGChildComponent> setChild(child: EGGChildConstructor<T>): T =
child(this, 0).also { this.child = it }


override fun enter(context: EGGContext): EGGContext {
var size = context.size
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.ewoudje.eggui.components.containers

import com.ewoudje.eggui.*
import com.ewoudje.eggui.components.*
import com.ewoudje.eggui.frontend.ChildBuilder
import com.ewoudje.eggui.frontend.EGGBuilderMarker
import com.ewoudje.eggui.frontend.invoke
import kotlin.reflect.KProperty

class StatefulContainer(
val block: StatefulContainer.() -> Unit,
override val parent: EGGContainerParent,
override val childId: Int,
): EGGSingleContainer {
override val attachment: EGGContainerAttachment = EGGContainerAttachment()
override var child: EGGChildComponent? = null
private set
private var childSize = Size.FILL
private val map = mutableMapOf<KProperty<*>, Any?>()
private val inits = mutableListOf<EGGInitPass>()
private var dirty = false

override fun <T : EGGChildComponent> setChild(child: EGGChildConstructor<T>): T =
child(this, 0).also { this.child = it }

override fun updateChildSize(size: Size) {
this.childSize = size
}

override fun getChildSize(): Size = childSize

override fun enter(context: EGGContext): EGGContext {
if (dirty) updateChild(context.position, context.size)
return context.new(listOf(context.position), listOf(context.size))
}

fun <T> newState(v: T) = StatePreparer(v, this)

private fun updateChild(pos: Pos, size: CalculatedSize) {
child = null
block()

child?.let {
for (pass in inits) {
EGGContext.traverse(it, EGGContext(listOf(pos), listOf(size), pass))
}
}
dirty = false
}

class StatePreparer<T>(private val defaultVal: T, private val container: StatefulContainer) {
operator fun provideDelegate(
thisRef: Any?,
prop: KProperty<*>
): State<T> {
val value = (container.map[prop] ?: defaultVal) as T
return State(value, container)
}
}

class State<T>(
private var value: T,
private val container: StatefulContainer
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
container.map[property] = value
container.dirty = true
}
}
}



@EGGBuilderMarker
fun <T: EGGContainer> T.stateful(block: StatefulContainer.() -> Unit): Unit =
ChildBuilder(this) { parent, id -> StatefulContainer(block, parent, id) }.invoke { block() }
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class VerticalContainer(
override val parent: EGGContainerParent,
override val childId: Int
) : EGGMultipleContainer {
override val attachment: EGGContainerAttachment = EGGContainerAttachment()
override val children = mutableListOf<EGGChildComponent>()
private val sizes = mutableListOf<Size>()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.ewoudje.eggui.components.elements

import com.ewoudje.eggui.*
import com.ewoudje.eggui.components.EGGContainer
import com.ewoudje.eggui.components.EGGContainerParent
import com.ewoudje.eggui.components.EGGFillingElement
import com.ewoudje.eggui.components.EGGFixedElement
import com.ewoudje.eggui.components.*
import com.ewoudje.eggui.frontend.ChildBuilder
import com.ewoudje.eggui.frontend.EGGBuilderMarker
import java.util.UUID
Expand All @@ -13,11 +10,13 @@ import kotlin.random.Random
data class RectangleAsset(val size: CalculatedSize, val color: Int): EGGRenderAsset

class RectangleElement(override val parent: EGGContainerParent, override val childId: Int) : EGGFillingElement, EGGFixedElement {
override val attachment: EGGElementAttachment = EGGElementAttachment()

var color = 0

override fun visit(context: EGGContext) {
when (context.pass) {
is EGGPass.Render -> {
is RenderPass -> {
val renderer = context.pass
renderer.renderAsset(RectangleAsset(context.size, color), context.position)
}
Expand All @@ -28,8 +27,4 @@ class RectangleElement(override val parent: EGGContainerParent, override val chi

@EGGBuilderMarker
val <T: EGGContainer> T.rectangle get() =
ChildBuilder(this, ::RectangleElement)

@EGGBuilderMarker
fun <T: EGGContainer> T.rectangle(color: Int = Random.nextInt()) =
ChildBuilder(this, ::RectangleElement).wrap { it.color = color }
ChildBuilder(this, ::RectangleElement)
16 changes: 14 additions & 2 deletions src/commonMain/kotlin/com/ewoudje/eggui/frontend/EGGBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.ewoudje.eggui.components.*
annotation class EGGBuilderMarker

@EGGBuilderMarker
class ChildBuilder< C: EGGContainer, T: EGGComponent>(
class ChildBuilder<C: EGGContainer, T: EGGComponent>(
val parent: C,
val constructor: EGGChildConstructor<T>
) {
Expand All @@ -33,4 +33,16 @@ operator fun <C, T> ChildBuilder<C, T>.invoke(block: T.() -> Unit): Unit
operator fun <C, T> ChildBuilder<C, T>.invoke(block: T.() -> Unit): Unit
where C: EGGSingleContainer,
T: EGGChildComponent
= parent.setChild(constructor).block()
= parent.setChild(constructor).block()


@EGGBuilderMarker
@JvmName("unknownContainerInvoke")
operator fun <C, T> ChildBuilder<C, T>.invoke(block: T.() -> Unit): Unit
where C: EGGContainer,
T: EGGChildComponent
= when(parent) {
is EGGMultipleContainer -> parent.addChild(constructor).block()
is EGGSingleContainer -> parent.setChild(constructor).block()
else -> throw IllegalStateException("Unknown container type")
}
10 changes: 10 additions & 0 deletions src/commonMain/kotlin/com/ewoudje/eggui/frontend/EGGCompiler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ private class Trace {
private fun traverse(comp: EGGComponent, ctx: EGGContext, trace: Trace) {
when (comp) {
is EGGMultipleContainer -> {

if (comp.attachment.onEnter(ctx.pass)) return

val newCtx = try {
comp.enter(ctx)
} catch (e: Exception) {
Expand All @@ -62,9 +65,13 @@ private fun traverse(comp: EGGComponent, ctx: EGGContext, trace: Trace) {
throw trace.exitError(e, comp)
}

if (comp.attachment.onExit(ctx.pass)) return

trace.exit(comp)
}
is EGGSingleContainer -> {
if (comp.attachment.onEnter(ctx.pass)) return

val newCtx = try {
comp.enter(ctx)
} catch (e: Exception) {
Expand All @@ -74,6 +81,8 @@ private fun traverse(comp: EGGComponent, ctx: EGGContext, trace: Trace) {
trace.enter(comp)
comp.child?.let { traverse(it, newCtx, trace) }

if (comp.attachment.onExit(ctx.pass)) return

try {
comp.exit(newCtx)
} catch (e: Exception) {
Expand All @@ -83,6 +92,7 @@ private fun traverse(comp: EGGComponent, ctx: EGGContext, trace: Trace) {
}
is EGGElement -> {
try {
if (comp.attachment.onVisit(ctx.pass)) return
comp.visit(ctx)
} catch (e: Exception) {
throw trace.visitError(e, comp)
Expand Down
20 changes: 20 additions & 0 deletions src/commonMain/kotlin/com/ewoudje/eggui/frontend/EGGEvents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ewoudje.eggui.frontend

import com.ewoudje.eggui.EGGPass
import com.ewoudje.eggui.components.EGGContainer
import com.ewoudje.eggui.components.EGGElement

fun EGGContainer.catchEnter(block: (EGGPass) -> Boolean) {
val visit = attachment.onEnter
attachment.onEnter = { block(it) || visit(it) }
}

fun EGGContainer.catchExit(block: (EGGPass) -> Boolean) {
val visit = attachment.onExit
attachment.onExit = { block(it) || visit(it) }
}

fun EGGElement.catchVisit(block: (EGGPass) -> Boolean): Unit {
val visit = attachment.onVisit
attachment.onVisit = { block(it) || visit(it) }
}
Loading

0 comments on commit cd22121

Please sign in to comment.