Skip to content

Commit

Permalink
reactive components redone
Browse files Browse the repository at this point in the history
  • Loading branch information
Hobbyshop committed Mar 8, 2024
1 parent 3105882 commit 8191bdb
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 81 deletions.
24 changes: 12 additions & 12 deletions src/main/kotlin/com/neptuneclient/voidui/ui/Component.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package com.neptuneclient.voidui.ui

/**
* Components are a small reusable chunk of drawables. Syntactically they are very similar to screens, but instead of being
* displayed on the screen, you can use them just like elements within other parts of your UI.
*
* There are two types of components:
* * [StaticComponent]: It is rendered once when the screen is built and is used to display static information.
* * [ReactiveComponent]: It can hold variables which will, when changed, will rebuild the component.
*/
sealed class Component(
var x: Int? = null,
var y: Int? = null,
width: Int? = null,
height: Int? = null
) {
var width = width ?: 0
var height = height ?: 0
var width: Int? = null,
var height: Int? = null
) : Drawable {

abstract fun build(): Component

val Number.cw
get() = (this.toDouble() / 100) * width

val Number.ch
get() = (this.toDouble() / 100) * height
abstract fun build(): Drawable

}
9 changes: 9 additions & 0 deletions src/main/kotlin/com/neptuneclient/voidui/ui/Drawable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.neptuneclient.voidui.ui

import com.neptuneclient.voidui.ui.elements.Element

/**
* For now this is just so [Component] and [Element] have the same superclass.
*/
interface Drawable {
}
39 changes: 10 additions & 29 deletions src/main/kotlin/com/neptuneclient/voidui/ui/ReactiveComponent.kt
Original file line number Diff line number Diff line change
@@ -1,40 +1,21 @@
package com.neptuneclient.voidui.ui

import com.neptuneclient.voidui.event.EventManager
import com.neptuneclient.voidui.event.Subscribe
import com.neptuneclient.voidui.event.impl.StateChangeEvent
import kotlin.properties.Delegates

/**
* @see Component
*/
abstract class ReactiveComponent : Component() {
val states = mutableListOf<State<*>>()

init {
EventManager.instance.register(this)
for (field in this.javaClass.declaredFields) {
if (field.type == State::class.java) {
field.isAccessible = true
val state = field.get(this) as State<*>
state.init()
states.add(state)
state.subscribe { newValue ->
// Here you can react to changes in the state.
// For example, you can rebuild the component.
rebuild()
}
for (field in javaClass.declaredFields) {
if (!field.isAnnotationPresent(State::class.java)) continue
val fieldObserver = Delegates.observable(field.get(this)) { _, _, new ->
this.build()
// TODO do proper rebuilding in the component tree
}
field.set(this, fieldObserver)
}
}

override fun build(): Component {
return this
}

open fun rebuild() {
// This method is called when a state changes.
// You can override it to rebuild the component.
}

@Subscribe(target = StateChangeEvent::class)
fun onStateChange(event: StateChangeEvent<*>) {
println("State changed from ${event.state.prev} to ${event.state.value}")
}
}
9 changes: 0 additions & 9 deletions src/main/kotlin/com/neptuneclient/voidui/ui/Screen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ import com.neptuneclient.voidui.VoidUI

abstract class Screen(private val void: VoidUI) {

var width = 0
var height = 0

abstract fun build(): Component

val Number.vw
get() = (this.toDouble() / 100) * width

val Number.vh
get() = (this.toDouble() / 100) * height

}
38 changes: 8 additions & 30 deletions src/main/kotlin/com/neptuneclient/voidui/ui/State.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,10 @@
package com.neptuneclient.voidui.ui

import com.neptuneclient.voidui.event.EventManager
import com.neptuneclient.voidui.event.impl.StateChangeEvent

class State<T : Any>(initial: T) {
var value: T = initial
set(value) {
field = value
changed()
}

var prev: T = initial
private val listeners = mutableListOf<(T) -> Unit>()

fun init() {
EventManager.instance.register(this)
println("State initialized")
}

fun changed() {
EventManager.instance.fire(
StateChangeEvent(this)
)
prev = this.value
listeners.forEach { it(value) } // Notify all listeners about the change
}

fun subscribe(listener: (T) -> Unit) {
listeners.add(listener)
}
}
/**
* Used in implementations of [ReactiveComponent] to declare fields as state.
*
* For more info check out [ReactiveComponent].
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class State()
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package com.neptuneclient.voidui.ui

/**
* @see Component
*/
abstract class StaticComponent : Component() {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package com.neptuneclient.voidui.ui.elements

sealed class Element {
import com.neptuneclient.voidui.ui.Drawable

/**
* Elements are the core building blocks of the library. They can not be created by the user and do not have children.
* Instead, they are rendered directly to the screen, and have also custom style properties (coming soon™).
*/
sealed class Element : Drawable {

abstract fun render()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.neptuneclient.voidui.ui.elements

class TestElement : Element() {

override fun render() {
println("please kill me")
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.neptuneclient.voidui.testmod.example

import com.neptuneclient.voidui.ui.Drawable
import com.neptuneclient.voidui.ui.ReactiveComponent
import com.neptuneclient.voidui.ui.State
import com.neptuneclient.voidui.ui.elements.TestElement

class Label : ReactiveComponent() {

@State
private var counter = 0

override fun build(): Drawable {
return TestElement()
}

}

0 comments on commit 8191bdb

Please sign in to comment.