ASMR/src/main/kotlin/net/shadowfacts/asmr/ui/ProgramBlockView.kt

154 lines
5.4 KiB
Kotlin
Raw Normal View History

package net.shadowfacts.asmr.ui
2019-08-10 02:39:01 +00:00
import net.minecraft.util.Identifier
import net.shadowfacts.asmr.ASMR
import net.shadowfacts.asmr.program.ExecutableBlock
import net.shadowfacts.asmr.program.ProgramBlock
import net.shadowfacts.asmr.program.ProgramBlockInput
import net.shadowfacts.asmr.program.ProgramBlockOutput
2019-08-10 02:39:01 +00:00
import net.shadowfacts.cacao.geometry.Axis
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.util.MouseButton
2019-08-10 02:39:01 +00:00
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.Label
2019-08-10 02:39:01 +00:00
import net.shadowfacts.cacao.view.StackView
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.View
import net.shadowfacts.kiwidsl.dsl
import no.birkett.kiwi.Constraint
import kotlin.math.max
/**
* @author shadowfacts
*/
2019-08-10 02:39:01 +00:00
class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distribution.CENTER, spacing = 4.0) {
companion object {
val emptyConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 0, v = 0)
val executionConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 7, v = 0)
val parameterConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 14, v = 0)
2019-08-10 02:39:01 +00:00
}
var incomingExecution: View? = null
var outgoingExeuction: View? = null
val inputViews = mutableMapOf<ProgramBlockInput<*>, View>()
val outputViews = mutableMapOf<ProgramBlockOutput<*>, View>()
var xConstraint: Constraint? = null
var yConstraint: Constraint? = null
var didCreateWidthConstraint = false
override fun wasAdded() {
super.wasAdded()
respondsToDragging = true
backgroundColor = Color.BLACK
zIndex = 10.0
2019-08-10 02:39:01 +00:00
val titleStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
val title = titleStack.addArrangedSubview(Label(block.translateName(), wrappingMode = Label.WrappingMode.NO_WRAP))
2019-08-10 02:39:01 +00:00
if (block is ExecutableBlock) {
val incomingTexture = if (block.executionFlow.prev == null) emptyConnection else executionConnection
2019-08-10 02:39:01 +00:00
incomingExecution = titleStack.addArrangedSubview(TextureView(incomingTexture), index = 0)
val outgoingTexture = if (block.executionFlow.next == null) emptyConnection else executionConnection
2019-08-10 02:39:01 +00:00
outgoingExeuction = titleStack.addArrangedSubview(TextureView(outgoingTexture))
}
solver.dsl {
2019-08-10 02:39:01 +00:00
// we have to constrain the titleStack height, because it's distribution is set to CENTER, so it doesn't do it itself
titleStack.heightAnchor equalTo title.heightAnchor
if (block is ExecutableBlock) {
incomingExecution!!.widthAnchor equalTo incomingExecution!!.heightAnchor
incomingExecution!!.widthAnchor equalTo 7
outgoingExeuction!!.widthAnchor equalTo outgoingExeuction!!.heightAnchor
outgoingExeuction!!.widthAnchor equalTo 7
}
}
for (i in 0 until max(block.inputs.size, block.outputs.size)) {
val hStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
block.inputs.getOrNull(i)?.let { input ->
2019-08-10 23:21:26 +00:00
val inputTexture = if (input.source == null) emptyConnection else parameterConnection
val inputView = hStack.addArrangedSubview(TextureView(inputTexture))
inputViews[input] = inputView
2019-08-10 23:21:26 +00:00
val inputLabel = hStack.addArrangedSubview(Label(input.translateName()))
solver.dsl {
hStack.heightAnchor equalTo inputLabel.heightAnchor
inputView.widthAnchor equalTo inputView.heightAnchor
inputView.widthAnchor equalTo 7
}
}
val spacingView = hStack.addArrangedSubview(View())
solver.dsl {
spacingView.widthAnchor equalTo 8
}
block.outputs.getOrNull(i)?.let { output ->
2019-08-10 23:21:26 +00:00
val outputLabel = hStack.addArrangedSubview(Label(output.translateName(), textAlignment = Label.TextAlignment.RIGHT))
val outputTexture = if (output.destinations.isEmpty()) emptyConnection else parameterConnection
val outputView = hStack.addArrangedSubview(TextureView(outputTexture))
outputViews[output] = outputView
solver.dsl {
hStack.heightAnchor equalTo outputLabel.heightAnchor
outputView.widthAnchor equalTo outputView.heightAnchor
outputView.widthAnchor equalTo 7
}
}
}
solver.dsl {
2019-08-10 02:39:01 +00:00
for (view in arrangedSubviews.drop(1)) {
widthAnchor.equalTo(view.widthAnchor, strength = STRONG)
}
}
updateDraggingConstraints()
}
override fun didLayout() {
super.didLayout()
// we want to constrain this view's width to be the same as the widest view in the vertical stack,
// but we don't know what view that is until after all subviews have been laid-out
if (!didCreateWidthConstraint) {
didCreateWidthConstraint = true
arrangedSubviews.maxBy { it.bounds.width }?.let { widestSubview ->
solver.dsl {
widthAnchor equalTo widestSubview.widthAnchor
}
window!!.layout()
}
}
}
override fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
block.position += delta
updateDraggingConstraints()
return true
}
private fun updateDraggingConstraints() {
if (xConstraint != null) solver.removeConstraint(xConstraint)
if (yConstraint != null) solver.removeConstraint(yConstraint)
solver.dsl {
xConstraint = (leftAnchor equalTo superview!!.leftAnchor + block.position.x)
yConstraint = (topAnchor equalTo superview!!.topAnchor + block.position.y)
}
window!!.layout()
}
2019-08-10 02:39:01 +00:00
override fun drawContent(mouse: Point, delta: Float) {
super.drawContent(mouse, delta)
}
}