From 089aaca1ea5899d3d636a28805ca2ffdf929a4cf Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 9 Aug 2019 14:36:12 -0400 Subject: [PATCH] Add View dragging and continue manager UI --- .../net/shadowfacts/asmr/TestCacaoScreen.kt | 59 +++++++++++++++---- .../shadowfacts/asmr/manager/ManagerBlock.kt | 10 +++- .../asmr/ui/ManagerViewController.kt | 31 ++++++---- .../shadowfacts/asmr/ui/ProgramBlockView.kt | 56 ++++++++++++++++++ .../net/shadowfacts/cacao/CacaoScreen.kt | 14 +++++ .../kotlin/net/shadowfacts/cacao/Window.kt | 32 +++++++++- .../net/shadowfacts/cacao/geometry/Point.kt | 4 ++ .../kotlin/net/shadowfacts/cacao/view/View.kt | 11 ++++ 8 files changed, 189 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/net/shadowfacts/asmr/ui/ProgramBlockView.kt diff --git a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt index f27841e..b2e269e 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt @@ -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 { diff --git a/src/main/kotlin/net/shadowfacts/asmr/manager/ManagerBlock.kt b/src/main/kotlin/net/shadowfacts/asmr/manager/ManagerBlock.kt index 9bf33c7..019f973 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/manager/ManagerBlock.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/manager/ManagerBlock.kt @@ -17,6 +17,7 @@ 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 @@ -35,8 +36,13 @@ class ManagerBlock: Block(Settings.of(Material.METAL)), BlockEntityProvider { private fun openManagerUI(managerBlockEntity: ManagerBlockEntity) { val vc = ManagerViewController(managerBlockEntity) val screen = CacaoScreen() - val window = screen.addWindow(Window(vc)) - MinecraftClient.getInstance().openScreen(screen) + 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 { diff --git a/src/main/kotlin/net/shadowfacts/asmr/ui/ManagerViewController.kt b/src/main/kotlin/net/shadowfacts/asmr/ui/ManagerViewController.kt index 13260d6..242e684 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/ui/ManagerViewController.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/ui/ManagerViewController.kt @@ -44,20 +44,25 @@ class ManagerViewController(val managerBlockEntity: ManagerBlockEntity): ViewCon val program = managerBlockEntity.program program.blocks.forEach { - val blockView = panel.addSubview(View()) - blockView.backgroundColor = Color.BLACK - val title = blockView.addSubview(Label(it.javaClass.simpleName)) - - createConstraints { - blockView.widthAnchor equalTo (title.widthAnchor + 8) - blockView.heightAnchor equalTo (title.heightAnchor + 8) - blockView.leftAnchor equalTo (panel.leftAnchor + 4 + it.position.x) - blockView.topAnchor equalTo (panel.topAnchor + 4 + it.position.y) - - title.leftAnchor equalTo (blockView.leftAnchor + 4) - title.topAnchor equalTo (blockView.topAnchor + 4) - } + panel.addSubview(ProgramBlockView(it)) } + +// program.blocks.forEach { +// val blockView = panel.addSubview(ProgramBlockView(it)) +// val blockView = panel.addSubview(View()) +// blockView.backgroundColor = Color.BLACK +// val title = blockView.addSubview(Label(it.javaClass.simpleName)) + +// createConstraints { +// blockView.widthAnchor equalTo (title.widthAnchor + 8) +// blockView.heightAnchor equalTo (title.heightAnchor + 8) +// blockView.leftAnchor equalTo (panel.leftAnchor + 4 + it.position.x) +// blockView.topAnchor equalTo (panel.topAnchor + 4 + it.position.y) + +// title.leftAnchor equalTo (blockView.leftAnchor + 4) +// title.topAnchor equalTo (blockView.topAnchor + 4) +// } +// } } } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/asmr/ui/ProgramBlockView.kt b/src/main/kotlin/net/shadowfacts/asmr/ui/ProgramBlockView.kt new file mode 100644 index 0000000..5ef9356 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/asmr/ui/ProgramBlockView.kt @@ -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 = 5.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() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt b/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt index 9561f80..0c5beda 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt @@ -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 + } + } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/Window.kt b/src/main/kotlin/net/shadowfacts/cacao/Window.kt index be2b225..89cde6b 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/Window.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/Window.kt @@ -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 + } + } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/geometry/Point.kt b/src/main/kotlin/net/shadowfacts/cacao/geometry/Point.kt index 9058c49..4afa7a0 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/geometry/Point.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/geometry/Point.kt @@ -13,4 +13,8 @@ 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) + } + } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/View.kt b/src/main/kotlin/net/shadowfacts/cacao/view/View.kt index dca513c..ef475f3 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/View.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/View.kt @@ -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. *