Compare commits
6 Commits
7cbcb267dd
...
37835b578d
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 37835b578d | |
Shadowfacts | 5c66e961d2 | |
Shadowfacts | 089aaca1ea | |
Shadowfacts | 946ebd7d9c | |
Shadowfacts | 200a9eea27 | |
Shadowfacts | b6982e04e4 |
|
@ -2,17 +2,36 @@ package net.shadowfacts.asmr
|
|||
|
||||
import net.fabricmc.api.ModInitializer
|
||||
import net.fabricmc.fabric.api.registry.CommandRegistry
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.server.command.CommandManager
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.asmr.manager.ManagerBlock
|
||||
import net.shadowfacts.asmr.manager.ManagerBlockEntity
|
||||
import net.shadowfacts.asmr.util.register
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object ASMR: ModInitializer {
|
||||
|
||||
const val modid = "asmr"
|
||||
|
||||
val managerBlock = ManagerBlock()
|
||||
val managerBlockItem = BlockItem(managerBlock, Item.Settings())
|
||||
val managerEntityType = BlockEntityType.Builder.create(Supplier { ManagerBlockEntity() }, managerBlock).build(null)
|
||||
|
||||
override fun onInitialize() {
|
||||
println("hello fabric")
|
||||
|
||||
Registry.BLOCK.register(managerBlock, Identifier(modid, "manager"))
|
||||
Registry.ITEM.register(managerBlockItem, Identifier(modid, "manager"))
|
||||
Registry.BLOCK_ENTITY.register(managerEntityType, Identifier(modid, "manager"))
|
||||
|
||||
CommandRegistry.INSTANCE.register(false) { dispatcher ->
|
||||
val command = CommandManager.literal("uitest").executes {
|
||||
try {
|
||||
|
|
|
@ -2,9 +2,14 @@ package net.shadowfacts.asmr
|
|||
|
||||
import net.shadowfacts.cacao.CacaoScreen
|
||||
import net.shadowfacts.cacao.Window
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.view.*
|
||||
import net.shadowfacts.cacao.view.button.Button
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import no.birkett.kiwi.Constraint
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -18,25 +23,55 @@ class TestCacaoScreen: CacaoScreen() {
|
|||
}
|
||||
|
||||
override fun viewDidLoad() {
|
||||
val container = view.addSubview(View())
|
||||
// val test = view.addSubview(object: View() {
|
||||
// override fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||
//
|
||||
// return true
|
||||
// }
|
||||
// })
|
||||
val draggable = view.addSubview(DraggableView())
|
||||
createConstraints {
|
||||
container.centerXAnchor equalTo view.centerXAnchor
|
||||
container.centerYAnchor equalTo view.centerYAnchor
|
||||
draggable.widthAnchor equalTo 50
|
||||
draggable.heightAnchor equalTo 25
|
||||
}
|
||||
embedChild(object: ViewController() {
|
||||
override fun loadView() {
|
||||
val button = Button(Label("test button"))
|
||||
button.handler = {
|
||||
println("button clicked")
|
||||
}
|
||||
this.view = button
|
||||
}
|
||||
}, container = container)
|
||||
}
|
||||
}
|
||||
addWindow(Window(viewController))
|
||||
}
|
||||
|
||||
class DraggableView: View() {
|
||||
init {
|
||||
backgroundColor = Color.WHITE
|
||||
}
|
||||
|
||||
var xOffset: Double = 0.0
|
||||
var yOffset: Double = 0.0
|
||||
var xConstraint: Constraint? = null
|
||||
var yConstraint: Constraint? = null
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
updateDraggingConstraints()
|
||||
}
|
||||
|
||||
override fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||
xOffset += delta.x
|
||||
yOffset += delta.y
|
||||
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 + xOffset)
|
||||
yConstraint = (topAnchor equalTo superview!!.topAnchor + yOffset)
|
||||
}
|
||||
window!!.layout()
|
||||
}
|
||||
}
|
||||
|
||||
// init {
|
||||
// addWindow(Window().apply {
|
||||
// val stack = addView(StackView(Axis.VERTICAL, StackView.Distribution.CENTER, spacing = 4.0).apply {
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package net.shadowfacts.asmr.manager
|
||||
|
||||
import net.fabricmc.api.EnvType
|
||||
import net.fabricmc.api.Environment
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockEntityProvider
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.asmr.ui.ManagerViewController
|
||||
import net.shadowfacts.cacao.CacaoScreen
|
||||
import net.shadowfacts.cacao.Window
|
||||
import no.birkett.kiwi.UnsatisfiableConstraintException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ManagerBlock: Block(Settings.of(Material.METAL)), BlockEntityProvider {
|
||||
|
||||
@Deprecated("")
|
||||
override fun activate(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult?): Boolean {
|
||||
if (world.isClient) {
|
||||
openManagerUI(world.getBlockEntity(pos) as ManagerBlockEntity)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private fun openManagerUI(managerBlockEntity: ManagerBlockEntity) {
|
||||
val vc = ManagerViewController(managerBlockEntity)
|
||||
val screen = CacaoScreen()
|
||||
try {
|
||||
val window = screen.addWindow(Window(vc))
|
||||
MinecraftClient.getInstance().openScreen(screen)
|
||||
} catch (e: UnsatisfiableConstraintException) {
|
||||
println("Couldn't open screen")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView): BlockEntity {
|
||||
return ManagerBlockEntity()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.shadowfacts.asmr.manager
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.Program
|
||||
import net.shadowfacts.asmr.program.ProgramType.Companion.INT
|
||||
import net.shadowfacts.asmr.program.blocks.ConstantBlock
|
||||
import net.shadowfacts.asmr.program.blocks.PrintBlock
|
||||
import net.shadowfacts.asmr.program.blocks.math.BinaryOperatorBlock
|
||||
import net.shadowfacts.asmr.program.blocks.math.BinaryOperatorBlock.Operation.DIVIDE
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ManagerBlockEntity: BlockEntity(ASMR.managerEntityType) {
|
||||
|
||||
val program = Program()
|
||||
|
||||
init {
|
||||
val left = program.addBlock(ConstantBlock(INT, 36)) {
|
||||
it.position = Point(0.0, 60.0)
|
||||
}
|
||||
val right = program.addBlock(ConstantBlock(INT, 9)) {
|
||||
it.position = Point(0.0, 120.0)
|
||||
}
|
||||
val divide = program.addBlock(BinaryOperatorBlock(INT, DIVIDE)) {
|
||||
it.left.source = left.output
|
||||
it.right.source = right.output
|
||||
it.position = Point(120.0, 0.0)
|
||||
}
|
||||
val print = program.addBlock(PrintBlock(INT)) {
|
||||
it.input.source = divide.output
|
||||
it.position = Point(240.0, 0.0)
|
||||
}
|
||||
|
||||
program.startBlock.nextExecutableBlock = divide
|
||||
divide.nextExecutableBlock = print
|
||||
}
|
||||
|
||||
fun activate() {
|
||||
program.execute()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class ExecutableBlock: ProgramBlock() {
|
||||
|
||||
var nextExecutableBlock: ExecutableBlock? = null
|
||||
|
||||
abstract fun execute()
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.shadowfacts.asmr.program.blocks.StartBlock
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class Program {
|
||||
|
||||
var startBlock = StartBlock().apply {
|
||||
position = Point.ORIGIN
|
||||
}
|
||||
val blocks = mutableListOf<ProgramBlock>()
|
||||
|
||||
fun execute() {
|
||||
var currentBlock: ExecutableBlock? = startBlock.nextExecutableBlock
|
||||
while (currentBlock != null) {
|
||||
currentBlock.execute()
|
||||
|
||||
currentBlock = currentBlock.nextExecutableBlock
|
||||
}
|
||||
}
|
||||
|
||||
fun <Block: ProgramBlock> addBlock(block: Block, init: (Block) -> Unit = {}): Block {
|
||||
init(block)
|
||||
blocks.add(block)
|
||||
return block
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class ProgramBlock {
|
||||
|
||||
var position: Point = Point.ORIGIN
|
||||
|
||||
abstract val inputs: Array<ProgramBlockInput<*>>
|
||||
abstract val outputs: Array<ProgramBlockOutput<*>>
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramBlockInput<Type: Any>(
|
||||
val type: ProgramType<Type>,
|
||||
val block: ProgramBlock,
|
||||
var source: ProgramBlockOutput<Type>? = null
|
||||
) {
|
||||
|
||||
val value: Type?
|
||||
get() = source?.value
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramBlockOutput<Type: Any>(
|
||||
val type: ProgramType<Type>,
|
||||
val block: ProgramBlock
|
||||
) {
|
||||
|
||||
lateinit var value: Type
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramType<Type> {
|
||||
companion object {
|
||||
val INT = ProgramType<Int>()
|
||||
val FLOAT = ProgramType<Float>()
|
||||
val STRING = ProgramType<String>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package net.shadowfacts.asmr.program.blocks
|
||||
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
import net.shadowfacts.asmr.program.ProgramType
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ConstantBlock<Type: Any>(
|
||||
val type: ProgramType<Type>,
|
||||
val value: Type
|
||||
): ProgramBlock() {
|
||||
|
||||
val output = ProgramBlockOutput(type, this).apply {
|
||||
value = this@ConstantBlock.value
|
||||
}
|
||||
|
||||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf()
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf(output)
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package net.shadowfacts.asmr.program.blocks
|
||||
|
||||
import net.shadowfacts.asmr.program.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
import net.shadowfacts.asmr.program.ProgramType
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class PrintBlock<Type: Any>(
|
||||
val type: ProgramType<Type>
|
||||
): ExecutableBlock() {
|
||||
|
||||
val input = ProgramBlockInput(type, this)
|
||||
|
||||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf(input)
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf()
|
||||
|
||||
override fun execute() {
|
||||
println(input.value)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package net.shadowfacts.asmr.program.blocks
|
||||
|
||||
import net.shadowfacts.asmr.program.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class StartBlock: ProgramBlock() {
|
||||
|
||||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf()
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf()
|
||||
|
||||
var nextExecutableBlock: ExecutableBlock? = null
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package net.shadowfacts.asmr.program.blocks.math
|
||||
|
||||
import net.shadowfacts.asmr.program.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
import net.shadowfacts.asmr.program.ProgramType
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class BinaryOperatorBlock<Type: Any>(
|
||||
val type: ProgramType<Type>,
|
||||
val operation: Operation
|
||||
): ExecutableBlock() {
|
||||
|
||||
init {
|
||||
if (type != ProgramType.INT && type != ProgramType.FLOAT) {
|
||||
throw RuntimeException("BinaryOperatorBlock type must be int or float")
|
||||
}
|
||||
}
|
||||
|
||||
val left = ProgramBlockInput(type, this)
|
||||
val right = ProgramBlockInput(type, this)
|
||||
|
||||
val output = ProgramBlockOutput(type, this)
|
||||
|
||||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf(left, right)
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf(output)
|
||||
|
||||
override fun execute() {
|
||||
if (type == ProgramType.INT) {
|
||||
val left = left.value as Int
|
||||
val right = right.value as Int
|
||||
output.value = when (operation) {
|
||||
Operation.ADD -> left + right
|
||||
Operation.SUBTRACT -> left - right
|
||||
Operation.MULTIPLY -> left * right
|
||||
Operation.DIVIDE -> left / right
|
||||
} as Type
|
||||
} else if (type == ProgramType.FLOAT) {
|
||||
val left = left.value as Float
|
||||
val right = right.value as Float
|
||||
output.value = when (operation) {
|
||||
Operation.ADD -> left + right
|
||||
Operation.SUBTRACT -> left - right
|
||||
Operation.MULTIPLY -> left * right
|
||||
Operation.DIVIDE -> left / right
|
||||
} as Type
|
||||
}
|
||||
}
|
||||
|
||||
enum class Operation {
|
||||
ADD, SUBTRACT, MULTIPLY, DIVIDE
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.shadowfacts.asmr.manager.ManagerBlockEntity
|
||||
import net.shadowfacts.cacao.geometry.Rect
|
||||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.texture.NinePatchTexture
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.NinePatchView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ManagerViewController(val managerBlockEntity: ManagerBlockEntity): ViewController() {
|
||||
|
||||
lateinit var panel: View
|
||||
|
||||
override fun viewDidLoad() {
|
||||
panel = view.addSubview(View())
|
||||
val background = panel.addSubview(NinePatchView(NinePatchTexture.PANEL_BG))
|
||||
val label = panel.addSubview(Label("test label"))
|
||||
val canvas = panel.addSubview(ProgramCanvasView(managerBlockEntity.program))
|
||||
|
||||
createConstraints {
|
||||
panel.widthAnchor equalTo (view.widthAnchor - 20)
|
||||
panel.heightAnchor equalTo (view.heightAnchor - 20)
|
||||
panel.centerXAnchor equalTo view.centerXAnchor
|
||||
panel.centerYAnchor equalTo view.centerYAnchor
|
||||
|
||||
background.leftAnchor equalTo panel.leftAnchor
|
||||
background.rightAnchor equalTo panel.rightAnchor
|
||||
background.topAnchor equalTo panel.topAnchor
|
||||
background.bottomAnchor equalTo panel.bottomAnchor
|
||||
|
||||
label.centerXAnchor equalTo view.centerXAnchor
|
||||
label.centerYAnchor equalTo view.centerYAnchor
|
||||
|
||||
canvas.widthAnchor equalTo (panel.widthAnchor - 8)
|
||||
canvas.heightAnchor equalTo (panel.heightAnchor - 8)
|
||||
canvas.centerXAnchor equalTo panel.centerXAnchor
|
||||
canvas.centerYAnchor equalTo panel.centerYAnchor
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import no.birkett.kiwi.Constraint
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramBlockView(val block: ProgramBlock): View() {
|
||||
|
||||
var xConstraint: Constraint? = null
|
||||
var yConstraint: Constraint? = null
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
respondsToDragging = true
|
||||
|
||||
backgroundColor = Color.BLACK
|
||||
zIndex = 10.0
|
||||
|
||||
val title = addSubview(Label(block.javaClass.simpleName))
|
||||
|
||||
solver.dsl {
|
||||
widthAnchor equalTo (title.widthAnchor + 8)
|
||||
heightAnchor equalTo (title.heightAnchor + 8)
|
||||
title.centerXAnchor equalTo centerXAnchor
|
||||
title.centerYAnchor equalTo centerYAnchor
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.shadowfacts.asmr.program.Program
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import net.shadowfacts.cacao.view.View
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramCanvasView(val program: Program): View() {
|
||||
|
||||
lateinit var blocks: Map<ProgramBlock, ProgramBlockView>
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
zIndex = 5.0
|
||||
|
||||
blocks = program.blocks.associateWith { ProgramBlockView(it) }
|
||||
blocks.values.forEach {
|
||||
addSubview(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun drawContent(mouse: Point, delta: Float) {
|
||||
super.drawContent(mouse, delta)
|
||||
|
||||
blocks.keys.forEach { block ->
|
||||
block.inputs
|
||||
.filter { it.source != null }
|
||||
.forEach { input ->
|
||||
val start = block.position
|
||||
val source = input.source!!
|
||||
val sourcePosition = source.block.position
|
||||
val end = Point(sourcePosition.x + blocks[source.block]!!.bounds.width, sourcePosition.y)
|
||||
|
||||
RenderHelper.drawLine(start, end, zIndex, 5f, Color.WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package net.shadowfacts.asmr.util
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
fun <T> Registry<T>.register(obj: T, identifier: Identifier) {
|
||||
Registry.register(this, identifier, obj)
|
||||
}
|
|
@ -80,4 +80,18 @@ open class CacaoScreen: Screen(LiteralText("CacaoScreen")) {
|
|||
}
|
||||
}
|
||||
|
||||
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
|
||||
val window = windows.lastOrNull()
|
||||
val startPoint = Point(mouseX, mouseY)
|
||||
val delta = Point(deltaX, deltaY)
|
||||
val result = window?.mouseDragged(startPoint, delta, MouseButton.fromMC(button))
|
||||
return result == true
|
||||
}
|
||||
|
||||
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
val window = windows.lastOrNull()
|
||||
val result = window?.mouseReleased(Point(mouseX, mouseY), MouseButton.fromMC(button))
|
||||
return result == true
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,6 @@ import net.shadowfacts.kiwidsl.dsl
|
|||
import no.birkett.kiwi.Constraint
|
||||
import no.birkett.kiwi.Solver
|
||||
import no.birkett.kiwi.Variable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A Window is the object at the top of a Cacao view hierarchy. It occupies the entirety of the Minecraft screen size
|
||||
|
@ -76,6 +75,8 @@ class Window(
|
|||
private var widthConstraint: Constraint? = null
|
||||
private var heightConstraint: Constraint? = null
|
||||
|
||||
private var currentDragReceiver: View? = null
|
||||
|
||||
init {
|
||||
createInternalConstraints()
|
||||
|
||||
|
@ -179,4 +180,33 @@ class Window(
|
|||
return false
|
||||
}
|
||||
|
||||
fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||
val currentlyDraggedView = this.currentDragReceiver
|
||||
if (currentlyDraggedView != null) {
|
||||
return currentlyDraggedView.mouseDragged(startPoint, delta, mouseButton)
|
||||
} else if (startPoint in viewController.view.frame) {
|
||||
val startInView = Point(startPoint.x - viewController.view.frame.left, startPoint.y - viewController.view.frame.top)
|
||||
lateinit var prevView: View
|
||||
var view = viewController.view.subviewsAtPoint(startInView).maxBy(View::zIndex)
|
||||
while (view != null && !view.respondsToDragging) {
|
||||
prevView = view
|
||||
val pointInView = viewController.view.convert(startInView, to = view)
|
||||
view = view.subviewsAtPoint(pointInView).maxBy(View::zIndex)
|
||||
}
|
||||
// this.currentlyDraggedView = viewController.view.subviewsAtPoint(startInView).maxBy(View::zIndex)
|
||||
this.currentDragReceiver = view ?: prevView
|
||||
return this.currentDragReceiver?.mouseDragged(startPoint, delta, mouseButton) ?: false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun mouseReleased(point: Point, mouseButton: MouseButton): Boolean {
|
||||
val currentlyDraggedView = this.currentDragReceiver
|
||||
if (currentlyDraggedView != null) {
|
||||
this.currentDragReceiver = null
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
|
@ -13,4 +13,12 @@ data class Point(val x: Double, val y: Double) {
|
|||
val ORIGIN = Point(0.0, 0.0)
|
||||
}
|
||||
|
||||
operator fun plus(other: Point): Point {
|
||||
return Point(x + other.x, y + other.y)
|
||||
}
|
||||
|
||||
operator fun minus(other: Point): Point {
|
||||
return Point(x - other.x, y - other.y)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,10 +3,13 @@ package net.shadowfacts.cacao.util
|
|||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawableHelper
|
||||
import net.minecraft.client.render.BufferBuilder
|
||||
import net.minecraft.client.render.Tessellator
|
||||
import net.minecraft.client.render.VertexFormat
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.geometry.Rect
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import org.lwjgl.opengl.GL11
|
||||
|
@ -45,6 +48,18 @@ object RenderHelper {
|
|||
draw(rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height)
|
||||
}
|
||||
|
||||
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
|
||||
if (disabled) return
|
||||
|
||||
GlStateManager.lineWidth(width)
|
||||
val tessellator = Tessellator.getInstance()
|
||||
val buffer = tessellator.bufferBuilder
|
||||
buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR)
|
||||
buffer.vertex(start.x, start.y, z).color(color).next()
|
||||
buffer.vertex(end.x, end.y, z).color(color).next()
|
||||
tessellator.draw()
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the bound texture with the given screen and texture position and size.
|
||||
*/
|
||||
|
@ -101,4 +116,9 @@ object RenderHelper {
|
|||
GlStateManager.color4f(r, g, b, alpha)
|
||||
}
|
||||
|
||||
private fun BufferBuilder.color(color: Color): BufferBuilder {
|
||||
color(color.alpha, color.red, color.green, color.blue)
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,8 @@ class Label(
|
|||
text: String,
|
||||
val shadow: Boolean = true,
|
||||
val maxLines: Int = 0,
|
||||
val wrappingMode: WrappingMode = WrappingMode.WRAP
|
||||
val wrappingMode: WrappingMode = WrappingMode.WRAP,
|
||||
val textAlignment: TextAlignment = TextAlignment.LEFT
|
||||
): View() {
|
||||
|
||||
companion object {
|
||||
|
@ -36,6 +37,10 @@ class Label(
|
|||
WRAP, NO_WRAP
|
||||
}
|
||||
|
||||
enum class TextAlignment {
|
||||
LEFT, CENTER, RIGHT
|
||||
}
|
||||
|
||||
/**
|
||||
* The text of this label. Mutating this field will update the intrinsic content size and trigger a layout.
|
||||
*/
|
||||
|
@ -79,8 +84,13 @@ class Label(
|
|||
}
|
||||
|
||||
for (i in 0 until lines.size) {
|
||||
val x = when (textAlignment) {
|
||||
TextAlignment.LEFT -> 0.0
|
||||
TextAlignment.CENTER -> (bounds.width + textRenderer.getStringWidth(lines[i])) / 2
|
||||
TextAlignment.RIGHT -> bounds.width - textRenderer.getStringWidth(lines[i])
|
||||
}
|
||||
val y = i * textRenderer.fontHeight
|
||||
drawFunc(lines[i], 0f, y.toFloat(), textColorARGB)
|
||||
drawFunc(lines[i], x.toFloat(), y.toFloat(), textColorARGB)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,8 @@ open class View() {
|
|||
*/
|
||||
var backgroundColor = Color.CLEAR
|
||||
|
||||
var respondsToDragging = false
|
||||
|
||||
/**
|
||||
* This view's parent view. If `null`, this view is a top-level view in the [Window].
|
||||
*/
|
||||
|
@ -333,6 +335,15 @@ open class View() {
|
|||
return false
|
||||
}
|
||||
|
||||
open fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||
val view = subviewsAtPoint(startPoint).maxBy(View::zIndex)
|
||||
if (view != null) {
|
||||
val startInView = convert(startPoint, to = view)
|
||||
return view.mouseDragged(startInView, delta, mouseButton)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given point in this view's coordinate system to the coordinate system of another view or the window.
|
||||
*
|
||||
|
|
|
@ -63,8 +63,12 @@ abstract class ViewController {
|
|||
*
|
||||
* This method should only be called by the framework. After the [view] property is set, the framework is
|
||||
* responsible for initializing its [View.window]/[View.solver] properties and calling [View.wasAdded].
|
||||
*
|
||||
* The default implementation simply creates a [View] and does nothing else with it.
|
||||
*/
|
||||
abstract fun loadView()
|
||||
open fun loadView() {
|
||||
view = View()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after the view is loaded, it's properties are initialized, and [View.wasAdded] has been
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.shadowfacts.asmr.program.blocks.ConstantBlock
|
||||
import net.shadowfacts.asmr.program.blocks.math.BinaryOperatorBlock
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramTests {
|
||||
|
||||
@Test
|
||||
fun testExecutionFlow() {
|
||||
val program = Program()
|
||||
val one = program.addBlock(ConstantBlock(ProgramType.INT, 3))
|
||||
val two = program.addBlock(ConstantBlock(ProgramType.INT, 7))
|
||||
val multiply = program.addBlock(BinaryOperatorBlock(ProgramType.INT, BinaryOperatorBlock.Operation.MULTIPLY)) {
|
||||
it.left.source = one.output
|
||||
it.right.source = two.output
|
||||
}
|
||||
|
||||
program.startBlock.nextExecutableBlock = multiply
|
||||
|
||||
program.execute()
|
||||
|
||||
assertEquals(21, multiply.output.value)
|
||||
}
|
||||
|
||||
}
|
|
@ -21,11 +21,7 @@ class CoordinateConversionTests {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewController = object: ViewController() {
|
||||
override fun loadView() {
|
||||
view = View()
|
||||
}
|
||||
}
|
||||
viewController = object: ViewController() {}
|
||||
window = Window(viewController)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,7 @@ class WindowLayoutTests {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewController = object: ViewController() {
|
||||
override fun loadView() {
|
||||
view = View()
|
||||
}
|
||||
}
|
||||
viewController = object: ViewController() {}
|
||||
window = Window(viewController)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,7 @@ class StackViewLayoutTests {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewController = object: ViewController() {
|
||||
override fun loadView() {
|
||||
view = View()
|
||||
}
|
||||
}
|
||||
viewController = object: ViewController() {}
|
||||
window = Window(viewController)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,7 @@ class ViewHoverTests {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewController = object: ViewController() {
|
||||
override fun loadView() {
|
||||
view = View()
|
||||
}
|
||||
}
|
||||
viewController = object: ViewController() {}
|
||||
window = Window(viewController)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue