package net.shadowfacts.asmr.ui 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.cacao.geometry.Axis import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.util.Color import net.shadowfacts.cacao.util.MouseButton import net.shadowfacts.cacao.util.texture.Texture import net.shadowfacts.cacao.view.Label 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 /** * @author shadowfacts */ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distribution.CENTER, spacing = 4.0) { companion object { val executionFlowInactiveTexture = Texture(Identifier(ASMR.modid, "textures/gui/programmer/execution_flow.png"), u = 0, v = 0) val executionFlowActiveTexture = Texture(Identifier(ASMR.modid, "textures/gui/programmer/execution_flow.png"), u = 7, v = 0) } var incomingExecution: View? = null var outgoingExeuction: View? = null var xConstraint: Constraint? = null var yConstraint: Constraint? = null override fun wasAdded() { super.wasAdded() respondsToDragging = true backgroundColor = Color.BLACK zIndex = 10.0 val titleStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER)) val title = titleStack.addArrangedSubview(Label(block.javaClass.simpleName)) if (block is ExecutableBlock) { val incomingTexture = if (block.executionFlow.prev == null) executionFlowInactiveTexture else executionFlowActiveTexture incomingExecution = titleStack.addArrangedSubview(TextureView(incomingTexture), index = 0) val outgoingTexture = if (block.executionFlow.next == null) executionFlowInactiveTexture else executionFlowActiveTexture outgoingExeuction = titleStack.addArrangedSubview(TextureView(outgoingTexture)) } val pairs = block.inputs.zip(block.outputs) val remainingInputs = if (block.inputs.size > block.outputs.size) block.inputs.drop(block.outputs.size) else listOf() val remainingOutputs = if (block.outputs.size > block.inputs.size) block.outputs.drop(block.inputs.size) else listOf() for ((input, output) in pairs) { val hStack = addArrangedSubview(StackView(Axis.HORIZONTAL, spacing = 8.0)) hStack.addArrangedSubview(Label(input.identifier.toString())) hStack.addArrangedSubview(Label(output.identifier.toString())) } for (input in remainingInputs) { addArrangedSubview(Label(input.identifier.toString())) } for (output in remainingOutputs) { addArrangedSubview(Label(output.identifier.toString(), textAlignment = Label.TextAlignment.RIGHT)) } solver.dsl { // 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 widthAnchor greaterThanOrEqualTo titleStack.widthAnchor if (block is ExecutableBlock) { incomingExecution!!.widthAnchor equalTo incomingExecution!!.heightAnchor incomingExecution!!.widthAnchor equalTo 7 outgoingExeuction!!.widthAnchor equalTo outgoingExeuction!!.heightAnchor outgoingExeuction!!.widthAnchor equalTo 7 } for (view in arrangedSubviews.drop(1)) { widthAnchor.equalTo(view.widthAnchor, strength = STRONG) } } updateDraggingConstraints() } 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() } override fun drawContent(mouse: Point, delta: Float) { super.drawContent(mouse, delta) } }