[orx-panel] Add WatchObjectDiv
This commit is contained in:
@@ -9,6 +9,7 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
demoImplementation("org.openrndr:openrndr-extensions:$openrndrVersion")
|
||||
demoImplementation("org.openrndr:openrndr-dialogs:$openrndrVersion")
|
||||
demoImplementation("com.google.code.gson:gson:$gsonVersion")
|
||||
|
||||
75
orx-panel/src/demo/kotlin/DemoWatchObjectDiv01.kt
Normal file
75
orx-panel/src/demo/kotlin/DemoWatchObjectDiv01.kt
Normal file
@@ -0,0 +1,75 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
import org.openrndr.panel.controlManager
|
||||
import org.openrndr.panel.elements.*
|
||||
import org.openrndr.panel.style.*
|
||||
|
||||
|
||||
fun main() = application {
|
||||
configure {
|
||||
width = 900
|
||||
height = 720
|
||||
}
|
||||
// A very simple state
|
||||
class State {
|
||||
var x = 0
|
||||
var y = 0
|
||||
var z = 0
|
||||
}
|
||||
program {
|
||||
// -- this block is for automation purposes only
|
||||
if (System.getProperty("takeScreenshot") == "true") {
|
||||
extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
val programState = State()
|
||||
val cm = controlManager {
|
||||
layout {
|
||||
styleSheet(has class_ "matrix") {
|
||||
this.width = 100.percent
|
||||
}
|
||||
|
||||
styleSheet(has class_ "row") {
|
||||
this.display = Display.FLEX
|
||||
this.flexDirection = FlexDirection.Row
|
||||
this.width = 100.percent
|
||||
|
||||
child(has type "slider") {
|
||||
this.width = 80.px
|
||||
}
|
||||
}
|
||||
|
||||
slider {
|
||||
label = "x"
|
||||
precision = 0
|
||||
bind(programState::x)
|
||||
}
|
||||
|
||||
slider {
|
||||
label = "y"
|
||||
precision = 0
|
||||
bind(programState::y)
|
||||
}
|
||||
|
||||
watchObjectDiv("matrix", watchObject = object {
|
||||
// for primitive types we have to use property references
|
||||
val x = programState::x
|
||||
val y = programState::y
|
||||
}) {
|
||||
for (y in 0 until watchObject.y.get()) {
|
||||
div("row") {
|
||||
for (x in 0 until watchObject.x.get()) {
|
||||
button() {
|
||||
label = "$x, $y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
extend(cm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.openrndr.panel.elements
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.yield
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.launch
|
||||
import org.openrndr.panel.elements.*
|
||||
import org.openrndr.panel.hash.watchHash
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
class WatchObjectDiv<T:Any>(
|
||||
val watchObject: T,
|
||||
private val builder: WatchObjectDiv<T>.(T) -> Unit
|
||||
) : Div(),
|
||||
DisposableElement {
|
||||
override var disposed: Boolean = false
|
||||
private var objectStateHash = watchHash(watchObject)
|
||||
private var watchJob: Job? = null
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
super.dispose()
|
||||
for (child in children) {
|
||||
child.parent = null
|
||||
(child as? DisposableElement)?.dispose()
|
||||
}
|
||||
children.clear()
|
||||
}
|
||||
|
||||
fun regenerate(force: Boolean = false) {
|
||||
var regenerate = force
|
||||
if (watchHash(watchObject) != objectStateHash) {
|
||||
regenerate = true
|
||||
}
|
||||
|
||||
if (regenerate) {
|
||||
for (child in children) {
|
||||
child.parent = null
|
||||
(child as? DisposableElement)?.dispose()
|
||||
}
|
||||
objectStateHash = watchHash(watchObject)
|
||||
children.clear()
|
||||
builder(watchObject)
|
||||
|
||||
requestRedraw()
|
||||
}
|
||||
}
|
||||
|
||||
fun checkJob() {
|
||||
if (watchJob == null) {
|
||||
watchJob = (root() as? Body)?.controlManager?.program?.launch {
|
||||
while (!disposed) {
|
||||
regenerate()
|
||||
yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun draw(drawer: Drawer) {
|
||||
checkJob()
|
||||
super.draw(drawer)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> Element.watchObjectDiv(
|
||||
vararg classes: String,
|
||||
watchObject: T,
|
||||
builder: WatchObjectDiv<T>.(T) -> Unit
|
||||
) : WatchObjectDiv<T> {
|
||||
val wd = WatchObjectDiv(watchObject, builder)
|
||||
wd.classes.addAll(classes.map { ElementClass(it) })
|
||||
this.append(wd)
|
||||
wd.regenerate(true)
|
||||
wd.checkJob()
|
||||
return wd
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.openrndr.panel.hash
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
|
||||
fun watchHash(toHash: Any): Int {
|
||||
var hash = 0
|
||||
for (property in toHash::class.declaredMemberProperties) {
|
||||
val v = (property.getter)(toHash)
|
||||
if (v is KProperty0<*>) {
|
||||
val pv = v.get()
|
||||
hash = 31 * hash + (pv?.hashCode() ?: 0)
|
||||
} else {
|
||||
hash = 31 * hash + (v?.hashCode() ?: 0)
|
||||
}
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user