Compare commits

...

6 Commits

30 changed files with 680 additions and 36 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}

View File

@ -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
}
}

View File

@ -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<*>>
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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>()
}
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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()
}
}

View File

@ -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)
}
}
}
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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.
*

View File

@ -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

View File

@ -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)
}
}

View File

@ -21,11 +21,7 @@ class CoordinateConversionTests {
@BeforeEach
fun setup() {
viewController = object: ViewController() {
override fun loadView() {
view = View()
}
}
viewController = object: ViewController() {}
window = Window(viewController)
}

View File

@ -21,11 +21,7 @@ class WindowLayoutTests {
@BeforeEach
fun setup() {
viewController = object: ViewController() {
override fun loadView() {
view = View()
}
}
viewController = object: ViewController() {}
window = Window(viewController)
}

View File

@ -23,11 +23,7 @@ class StackViewLayoutTests {
@BeforeEach
fun setup() {
viewController = object: ViewController() {
override fun loadView() {
view = View()
}
}
viewController = object: ViewController() {}
window = Window(viewController)
}

View File

@ -31,11 +31,7 @@ class ViewHoverTests {
@BeforeEach
fun setup() {
viewController = object: ViewController() {
override fun loadView() {
view = View()
}
}
viewController = object: ViewController() {}
window = Window(viewController)
}