From e4fc677dc1d38cb6ea40a5a439a1bc5211001e9c Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 28 Jun 2019 11:12:46 -0400 Subject: [PATCH] Start adding ViewControllers --- .../net/shadowfacts/asmr/TestCacaoScreen.kt | 222 ++++++++++-------- .../kotlin/net/shadowfacts/cacao/Window.kt | 89 +++---- .../util/properties/ObservableLazyProperty.kt | 20 ++ .../cacao/view/button/DropdownButton.kt | 84 +++---- .../cacao/viewcontroller/ViewController.kt | 91 +++++++ 5 files changed, 300 insertions(+), 206 deletions(-) create mode 100644 src/main/kotlin/net/shadowfacts/cacao/util/properties/ObservableLazyProperty.kt create mode 100644 src/main/kotlin/net/shadowfacts/cacao/viewcontroller/ViewController.kt diff --git a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt index b279619..3d35267 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/TestCacaoScreen.kt @@ -1,17 +1,9 @@ package net.shadowfacts.asmr -import net.minecraft.util.Identifier -import net.shadowfacts.asmr.util.RedstoneMode -import net.shadowfacts.kiwidsl.dsl import net.shadowfacts.cacao.CacaoScreen import net.shadowfacts.cacao.Window -import net.shadowfacts.cacao.geometry.Axis -import net.shadowfacts.cacao.geometry.Size -import net.shadowfacts.cacao.util.Color -import net.shadowfacts.cacao.util.texture.NinePatchTexture -import net.shadowfacts.cacao.util.texture.Texture import net.shadowfacts.cacao.view.* -import net.shadowfacts.cacao.view.button.DropdownButton +import net.shadowfacts.cacao.viewcontroller.ViewController /** * @author shadowfacts @@ -19,103 +11,125 @@ import net.shadowfacts.cacao.view.button.DropdownButton class TestCacaoScreen: CacaoScreen() { init { - addWindow(Window().apply { - val stack = addView(StackView(Axis.VERTICAL, StackView.Distribution.CENTER, spacing = 4.0).apply { - backgroundColor = Color.WHITE - }) - val red = stack.addArrangedSubview(TextureView(Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16)).apply { - intrinsicContentSize = Size(50.0, 50.0) - }) - val green = stack.addArrangedSubview(NinePatchView(NinePatchTexture.PANEL_BG).apply { - intrinsicContentSize = Size(75.0, 100.0) - }) - val blue = stack.addArrangedSubview(View().apply { - intrinsicContentSize = Size(50.0, 50.0) - backgroundColor = Color(0x0000ff) - }) - val purple = blue.addSubview(DropdownButton( - initialValue = RedstoneMode.HIGH, - allValues = RedstoneMode.values().asIterable(), - createView = { Label(it.name) }, - updateView = { newValue, label -> label.text = newValue.name } - ).apply { - handler = { - println("dropdown value: ${it.value}") - val dialog = DialogView( - "New redstone mode", - it.value.name, - arrayOf(DialogView.DefaultButtonType.OK), - Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16), - buttonCallback = { _, window -> - window.removeFromScreen() - } - ) - val dialogWindow = Window() - dialogWindow.addView(dialog) - this@TestCacaoScreen.addWindow(dialogWindow) - } - }) - - val label = addView(Label("test ".repeat(100), maxLines = 5)) - - solver.dsl { - stack.topAnchor equalTo 0 - stack.centerXAnchor equalTo this@apply.centerXAnchor - stack.widthAnchor equalTo 100 - purple.centerXAnchor equalTo blue.centerXAnchor - purple.centerYAnchor equalTo blue.centerYAnchor -// purple.widthAnchor equalTo 50 - - label.topAnchor equalTo 0 - label.leftAnchor equalTo 0 - label.widthAnchor equalTo 100 + val viewController = object: ViewController() { + override fun loadView() { + this.view = View() } - -// val red = addView(View().apply { -// backgroundColor = Color(0xff0000) -// }) -// val green = addView(View().apply { -// backgroundColor = Color(0x00ff00) -// }) -// val blue = addView(View().apply { -// backgroundColor = Color(0x0000ff) -// }) -// val purple = green.addSubview(View().apply { -// backgroundColor = Color(0x800080) -// }) -// purple.intrinsicContentSize = Size(width = 150.0, height = 150.0) -// val label = purple.addSubview(Label("Hello, world!").apply { -// textColor = Color.WHITE -// }) -// -// solver.dsl { -// red.leftAnchor equalTo 0 -// red.widthAnchor equalTo 200 -// red.topAnchor equalTo 0 -// red.heightAnchor equalTo 100 -// -// green.leftAnchor equalTo (red.leftAnchor + red.widthAnchor + 20) -// green.widthAnchor equalTo red.widthAnchor -// green.topAnchor equalTo 0 -// green.heightAnchor equalTo (red.heightAnchor + 100) -// -// blue.leftAnchor equalTo green.leftAnchor -// blue.widthAnchor equalTo green.widthAnchor -// blue.topAnchor equalTo (green.topAnchor + green.heightAnchor) -// blue.heightAnchor equalTo 50 -// -//// purple.widthAnchor equalTo 100 -//// purple.heightAnchor equalTo 100 -// purple.centerXAnchor equalTo green.centerXAnchor -// purple.centerYAnchor equalTo green.centerYAnchor -// -// label.centerXAnchor equalTo purple.centerXAnchor -// label.centerYAnchor equalTo purple.centerYAnchor -// } -// -// layout() - }) + override fun viewDidLoad() { + val labelContainer = view.addSubview(View()) + createConstraints { + labelContainer.centerXAnchor equalTo view.centerXAnchor + labelContainer.centerYAnchor equalTo view.centerYAnchor + } + embedChild(object: ViewController() { + override fun loadView() { + this.view = Label("test child") + } + }, container = labelContainer) + } + } + addWindow(Window(viewController)) } +// init { +// addWindow(Window().apply { +// val stack = addView(StackView(Axis.VERTICAL, StackView.Distribution.CENTER, spacing = 4.0).apply { +// backgroundColor = Color.WHITE +// }) +// val red = stack.addArrangedSubview(TextureView(Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16)).apply { +// intrinsicContentSize = Size(50.0, 50.0) +// }) +// val green = stack.addArrangedSubview(NinePatchView(NinePatchTexture.PANEL_BG).apply { +// intrinsicContentSize = Size(75.0, 100.0) +// }) +// val blue = stack.addArrangedSubview(View().apply { +// intrinsicContentSize = Size(50.0, 50.0) +// backgroundColor = Color(0x0000ff) +// }) +// val purple = blue.addSubview(DropdownButton( +// initialValue = RedstoneMode.HIGH, +// allValues = RedstoneMode.values().asIterable(), +// createView = { Label(it.name) }, +// updateView = { newValue, label -> label.text = newValue.name } +// ).apply { +// handler = { +// println("dropdown value: ${it.value}") +// val dialog = DialogView( +// "New redstone mode", +// it.value.name, +// arrayOf(DialogView.DefaultButtonType.OK), +// Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16), +// buttonCallback = { _, window -> +// window.removeFromScreen() +// } +// ) +// val dialogWindow = Window() +// dialogWindow.addView(dialog) +// this@TestCacaoScreen.addWindow(dialogWindow) +// } +// }) +// +// val label = addView(Label("test ".repeat(100), maxLines = 5)) +// +// solver.dsl { +// stack.topAnchor equalTo 0 +// stack.centerXAnchor equalTo this@apply.centerXAnchor +// stack.widthAnchor equalTo 100 +// purple.centerXAnchor equalTo blue.centerXAnchor +// purple.centerYAnchor equalTo blue.centerYAnchor +//// purple.widthAnchor equalTo 50 +// +// label.topAnchor equalTo 0 +// label.leftAnchor equalTo 0 +// label.widthAnchor equalTo 100 +// } +// +// +//// val red = addView(View().apply { +//// backgroundColor = Color(0xff0000) +//// }) +//// val green = addView(View().apply { +//// backgroundColor = Color(0x00ff00) +//// }) +//// val blue = addView(View().apply { +//// backgroundColor = Color(0x0000ff) +//// }) +//// val purple = green.addSubview(View().apply { +//// backgroundColor = Color(0x800080) +//// }) +//// purple.intrinsicContentSize = Size(width = 150.0, height = 150.0) +//// val label = purple.addSubview(Label("Hello, world!").apply { +//// textColor = Color.WHITE +//// }) +//// +//// solver.dsl { +//// red.leftAnchor equalTo 0 +//// red.widthAnchor equalTo 200 +//// red.topAnchor equalTo 0 +//// red.heightAnchor equalTo 100 +//// +//// green.leftAnchor equalTo (red.leftAnchor + red.widthAnchor + 20) +//// green.widthAnchor equalTo red.widthAnchor +//// green.topAnchor equalTo 0 +//// green.heightAnchor equalTo (red.heightAnchor + 100) +//// +//// blue.leftAnchor equalTo green.leftAnchor +//// blue.widthAnchor equalTo green.widthAnchor +//// blue.topAnchor equalTo (green.topAnchor + green.heightAnchor) +//// blue.heightAnchor equalTo 50 +//// +////// purple.widthAnchor equalTo 100 +////// purple.heightAnchor equalTo 100 +//// purple.centerXAnchor equalTo green.centerXAnchor +//// purple.centerYAnchor equalTo green.centerYAnchor +//// +//// label.centerXAnchor equalTo purple.centerXAnchor +//// label.centerYAnchor equalTo purple.centerYAnchor +//// } +//// +//// layout() +// }) +// } + } \ 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 353c2da..2189f80 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/Window.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/Window.kt @@ -3,6 +3,7 @@ package net.shadowfacts.cacao import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.util.MouseButton import net.shadowfacts.cacao.view.View +import net.shadowfacts.cacao.viewcontroller.ViewController import net.shadowfacts.kiwidsl.dsl import no.birkett.kiwi.Constraint import no.birkett.kiwi.Solver @@ -17,7 +18,7 @@ import java.util.* * * @author shadowfacts */ -class Window { +class Window(val viewController: ViewController) { /** * The screen that this window belongs to. @@ -68,18 +69,25 @@ class Window { private var widthConstraint: Constraint? = null private var heightConstraint: Constraint? = null - // _views is the internal, mutable object, since we only want it to be mutated by the add/removeView methods - private val _views = LinkedList() - /** - * The list of top-level views in this window. - * This list should never be modified directly, only by calling the [addView]/[removeView] methods. - */ - val views: List = _views - - private var viewsSortedByZIndex: List = listOf() - init { createInternalConstraints() + + viewController.window = this + viewController.loadView() + + viewController.view.window = this + viewController.view.solver = solver + viewController.view.wasAdded() + viewController.createConstraints { + viewController.view.leftAnchor equalTo leftAnchor + viewController.view.rightAnchor equalTo rightAnchor + viewController.view.topAnchor equalTo topAnchor + viewController.view.bottomAnchor equalTo bottomAnchor + } + + viewController.viewDidLoad() + + layout() } /** @@ -116,47 +124,9 @@ class Window { * Convenience method that removes this window from its [screen]. */ fun removeFromScreen() { + viewController.viewWillDisappear() screen.removeWindow(this) - } - - /** - * Adds the given view as a top-level view in this window. - * - * @param view The view to add. - * @return The same view, as a convenience. - */ - fun addView(view: T): T { - _views.add(view) - viewsSortedByZIndex = views.sortedBy(View::zIndex) - - view.window = this - view.solver = solver - - view.wasAdded() - - return view - } - - /** - * Finds all views in this window at the given point. - * - * @param point The point to find views at, in the coordinate system of the window. - * @return All views that contain the point. - */ - fun viewsAtPoint(point: Point): List { - return views.filter { point in it.frame } - } - - /** - * Attempts to find a top level view of this window that contains the given point. - * If there are multiple overlapping views, which one this method returns is undefined. - * [viewsAtPoint] may be used, and the resulting List sorted by [View.zIndex]. - * - * @param point The point to find views at, in the coordinate system of the window. - * @return the Veiw, if any, that contain the given point. - */ - fun viewAtPoint(point: Point): View? { - return views.firstOrNull { point in it.frame } + viewController.viewDidDisappear() } /** @@ -165,7 +135,9 @@ class Window { */ fun layout() { solver.updateVariables() - views.forEach(View::didLayout) + viewController.viewWillLayoutSubviews() + viewController.view.didLayout() + viewController.viewDidLayoutSubviews() } /** @@ -176,10 +148,8 @@ class Window { * @param delta The time elapsed since the last frame. */ fun draw(mouse: Point, delta: Float) { - viewsSortedByZIndex.forEach { - val mouseInView = Point(mouse.x - it.frame.left, mouse.y - it.frame.top) - it.draw(mouseInView, delta) - } + val mouseInView = Point(mouse.x - viewController.view.frame.left, mouse.y - viewController.view.frame.top) + viewController.view.draw(mouseInView, delta) } /** @@ -191,10 +161,9 @@ class Window { * @return Whether the mouse click was handled by a view. */ fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean { - val view = viewsAtPoint(point).maxBy(View::zIndex) - if (view != null) { - val pointInView = Point(point.x - view.frame.left, point.y - view.frame.top) - return view.mouseClicked(pointInView, mouseButton) + if (point in viewController.view.frame) { + val mouseInView = Point(point.x - viewController.view.frame.left, point.y - viewController.view.frame.top) + return viewController.view.mouseClicked(mouseInView, mouseButton) } else { // remove the window from the screen when the mouse clicks outside the window and this is not the primary window if (screen.windows.size > 1) { diff --git a/src/main/kotlin/net/shadowfacts/cacao/util/properties/ObservableLazyProperty.kt b/src/main/kotlin/net/shadowfacts/cacao/util/properties/ObservableLazyProperty.kt new file mode 100644 index 0000000..a912b59 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/cacao/util/properties/ObservableLazyProperty.kt @@ -0,0 +1,20 @@ +package net.shadowfacts.cacao.util.properties + +import kotlin.reflect.KProperty + +/** + * @author shadowfacts + */ +class ObservableLazyProperty(val create: () -> Value, val onCreate: () -> Unit) { + + var storage: Value? = null + + operator fun getValue(thisRef: Any, property: KProperty<*>): Value { + if (storage == null) { + storage = create() + onCreate() + } + return storage!! + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/cacao/view/button/DropdownButton.kt b/src/main/kotlin/net/shadowfacts/cacao/view/button/DropdownButton.kt index 6da1a3e..619392b 100644 --- a/src/main/kotlin/net/shadowfacts/cacao/view/button/DropdownButton.kt +++ b/src/main/kotlin/net/shadowfacts/cacao/view/button/DropdownButton.kt @@ -88,48 +88,48 @@ class DropdownButton( } private fun showDropdown() { - val dropdownWindow = window.screen.addWindow(Window()) - val dropdownBackground = dropdownWindow.addView(NinePatchView(NinePatchTexture.BUTTON_BG).apply { - zIndex = -1.0 - }) - val stack = dropdownWindow.addView(StackView(Axis.VERTICAL, StackView.Distribution.FILL)) - lateinit var selectedButton: View - val buttons = mutableListOf