Add program parameter linking UI
This commit is contained in:
parent
971c41ed2f
commit
233a83f368
|
@ -25,12 +25,12 @@ class ManagerBlockEntity: BlockEntity(ASMR.managerEntityType) {
|
|||
it.position = Point(0.0, 120.0)
|
||||
}
|
||||
val divide = program.addBlock(BinaryOperatorBlock(INT, DIVIDE)) {
|
||||
it.left.link(from = left.output)
|
||||
it.right.link(from = right.output)
|
||||
// it.left.link(from = left.output)
|
||||
// it.right.link(from = right.output)
|
||||
it.position = Point(120.0, 0.0)
|
||||
}
|
||||
val print = program.addBlock(PrintBlock(INT)) {
|
||||
it.input.link(from = divide.output)
|
||||
// it.input.link(from = divide.output)
|
||||
it.position = Point(240.0, 0.0)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import net.shadowfacts.cacao.view.TextureView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramBlockParamView(val input: ProgramBlockInput<*>?, val output: ProgramBlockOutput<*>?): View() {
|
||||
|
||||
companion object {
|
||||
val emptyConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 0, v = 0)
|
||||
val parameterConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 14, v = 0)
|
||||
}
|
||||
|
||||
lateinit var textureView: TextureView
|
||||
|
||||
constructor(input: ProgramBlockInput<*>): this(input, null)
|
||||
constructor(output: ProgramBlockOutput<*>): this(null, output)
|
||||
|
||||
init {
|
||||
if (input == null && output == null) {
|
||||
throw RuntimeException("One of input or output must be non-null")
|
||||
}
|
||||
}
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
textureView = addSubview(TextureView(emptyConnection))
|
||||
updateTexture()
|
||||
|
||||
solver.dsl {
|
||||
textureView.leftAnchor equalTo leftAnchor
|
||||
textureView.rightAnchor equalTo rightAnchor
|
||||
textureView.topAnchor equalTo topAnchor
|
||||
textureView.bottomAnchor equalTo bottomAnchor
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTexture() {
|
||||
val active = if (input != null) input.source != null else output!!.destinations.isNotEmpty()
|
||||
textureView.texture = if (active) parameterConnection else emptyConnection
|
||||
}
|
||||
|
||||
}
|
|
@ -33,8 +33,8 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
var incomingExecution: View? = null
|
||||
var outgoingExeuction: View? = null
|
||||
|
||||
val inputViews = mutableMapOf<ProgramBlockInput<*>, View>()
|
||||
val outputViews = mutableMapOf<ProgramBlockOutput<*>, View>()
|
||||
val inputViews = mutableMapOf<ProgramBlockInput<*>, ProgramBlockParamView>()
|
||||
val outputViews = mutableMapOf<ProgramBlockOutput<*>, ProgramBlockParamView>()
|
||||
|
||||
var xConstraint: Constraint? = null
|
||||
var yConstraint: Constraint? = null
|
||||
|
@ -73,8 +73,9 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
val hStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
|
||||
|
||||
block.inputs.getOrNull(i)?.let { input ->
|
||||
val inputTexture = if (input.source == null) emptyConnection else parameterConnection
|
||||
val inputView = hStack.addArrangedSubview(TextureView(inputTexture))
|
||||
// val inputTexture = if (input.source == null) emptyConnection else parameterConnection
|
||||
// val inputView = hStack.addArrangedSubview(TextureView(inputTexture))
|
||||
val inputView = hStack.addArrangedSubview(ProgramBlockParamView(input))
|
||||
inputViews[input] = inputView
|
||||
val inputLabel = hStack.addArrangedSubview(Label(input.translateName()))
|
||||
solver.dsl {
|
||||
|
@ -92,8 +93,9 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
|
||||
block.outputs.getOrNull(i)?.let { output ->
|
||||
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))
|
||||
// val outputTexture = if (output.destinations.isEmpty()) emptyConnection else parameterConnection
|
||||
// val outputView = hStack.addArrangedSubview(TextureView(outputTexture))
|
||||
val outputView = hStack.addArrangedSubview(ProgramBlockParamView(output))
|
||||
outputViews[output] = outputView
|
||||
solver.dsl {
|
||||
hStack.heightAnchor equalTo outputLabel.heightAnchor
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.shadowfacts.asmr.program.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.Program
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.asmr.program.*
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import net.shadowfacts.cacao.view.View
|
||||
|
||||
|
@ -19,6 +18,8 @@ class ProgramCanvasView(val program: Program): View() {
|
|||
private val executionFlowStartLinks = mutableMapOf<ExecutableBlock, Pair<Point, Point>>()
|
||||
private val parameterLinks = mutableMapOf<ProgramBlock, Pair<Point, Point>>()
|
||||
|
||||
private var currentPartialLink: PartialLink? = null
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
|
@ -76,6 +77,91 @@ class ProgramCanvasView(val program: Program): View() {
|
|||
for ((start, end) in parameterLinks.values) {
|
||||
RenderHelper.drawLine(start, end, zIndex, 5f, Color.RED)
|
||||
}
|
||||
|
||||
val currentPartialLink = currentPartialLink
|
||||
when (currentPartialLink) {
|
||||
is ParamInputPartialLink<*>, is ParamOutputPartialLink<*> -> {
|
||||
RenderHelper.drawLine(currentPartialLink.startPoint, mouse, zIndex, 5f, Color.RED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||
for ((block, blockView) in blocks) {
|
||||
if (convert(point, to = blockView) !in blockView.bounds) continue
|
||||
|
||||
for ((input, inputView) in blockView.inputViews) {
|
||||
if (convert(point, to = inputView) in inputView.bounds) {
|
||||
return inputViewClicked(block, input, inputView)
|
||||
}
|
||||
}
|
||||
for ((output, outputView) in blockView.outputViews) {
|
||||
if (convert(point, to = outputView) in outputView.bounds) {
|
||||
return outputViewClicked(block, output, outputView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.mouseClicked(point, mouseButton)
|
||||
}
|
||||
|
||||
private fun <Type: Any> inputViewClicked(block: ProgramBlock, input: ProgramBlockInput<Type>, inputView: ProgramBlockParamView): Boolean {
|
||||
val currentPartialLink = currentPartialLink
|
||||
val result = if (currentPartialLink == null) {
|
||||
// no partial link in progress, begin a new one
|
||||
this.currentPartialLink = ParamInputPartialLink(input, inputView, inputView.convert(inputView.bounds.center, to = this))
|
||||
true
|
||||
} else if (currentPartialLink is ParamOutputPartialLink<*> && currentPartialLink.output.type == input.type) {
|
||||
// current link in progress originated with an output param of same type as clicked input, so complete it
|
||||
// we can ignore the unchecked cast because we checked it ourselves above by comparing ProgramTypes, but the compiler doesn't know that
|
||||
@Suppress("NAME_SHADOWING", "UNCHECKED_CAST")
|
||||
val currentPartialLink = currentPartialLink as ParamOutputPartialLink<Type>
|
||||
currentPartialLink.output.link(to = input)
|
||||
currentPartialLink.view.updateTexture()
|
||||
inputView.updateTexture()
|
||||
this.currentPartialLink = null
|
||||
true
|
||||
} else {
|
||||
// otherwise, click always fails
|
||||
false
|
||||
}
|
||||
|
||||
if (result) {
|
||||
updateBlockLinks()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun <Type: Any> outputViewClicked(block: ProgramBlock, output: ProgramBlockOutput<Type>, outputView: ProgramBlockParamView): Boolean {
|
||||
val currentPartialLink = currentPartialLink
|
||||
val result = if (currentPartialLink == null) {
|
||||
this.currentPartialLink = ParamOutputPartialLink(output, outputView, outputView.convert(outputView.bounds.center, to = this))
|
||||
true
|
||||
} else if (currentPartialLink is ParamInputPartialLink<*> && currentPartialLink.input.type == output.type) {
|
||||
// current link in progress originated with an input param of same type as clicked output, so complete it
|
||||
// we can ignore the unchecked cast because we checked it ourselves above by comparing ProgramTypes, but the compiler doesn't know that
|
||||
@Suppress("NAME_SHADOWING", "UNCHECKED_CAST")
|
||||
val currentPartialLink = currentPartialLink as ParamInputPartialLink<Type>
|
||||
currentPartialLink.input.link(from = output)
|
||||
currentPartialLink.view.updateTexture()
|
||||
outputView.updateTexture()
|
||||
this.currentPartialLink = null
|
||||
true
|
||||
} else {
|
||||
// otherwise, click always fails
|
||||
false
|
||||
}
|
||||
|
||||
if (result) {
|
||||
updateBlockLinks()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
open class PartialLink(val view: ProgramBlockParamView, val startPoint: Point)
|
||||
class ParamInputPartialLink<Type: Any>(val input: ProgramBlockInput<Type>, view: ProgramBlockParamView, startPoint: Point): PartialLink(view, startPoint)
|
||||
class ParamOutputPartialLink<Type: Any>(val output: ProgramBlockOutput<Type>, view: ProgramBlockParamView, startPoint: Point): PartialLink(view, startPoint)
|
||||
// class ExecutionStartPartialLink<Type: Any>(val start: ExecutableBlock): PartialLink
|
||||
// class ExecutionEndPartialLink<Type: Any>(val end: ExecutableBlock): PartialLink
|
||||
|
||||
}
|
Loading…
Reference in New Issue