PhysicalConnectivity/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt

186 lines
5.1 KiB
Kotlin
Raw Normal View History

2021-02-19 04:12:43 +00:00
package net.shadowfacts.cacao
import net.minecraft.client.MinecraftClient
2021-02-19 04:12:43 +00:00
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.sound.SoundEvents
import net.minecraft.text.LiteralText
2021-02-28 02:48:40 +00:00
import net.minecraft.text.Text
2021-02-19 04:12:43 +00:00
import net.shadowfacts.cacao.geometry.Point
2021-02-27 19:02:30 +00:00
import net.shadowfacts.cacao.util.KeyModifiers
2021-02-19 04:12:43 +00:00
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.RenderHelper
2021-02-19 04:27:18 +00:00
import net.shadowfacts.cacao.window.Window
import org.lwjgl.glfw.GLFW
2021-02-19 04:12:43 +00:00
import java.util.*
/**
* This class serves as the bridge between Cacao and a Minecraft [Screen]. It renders Cacao [Window]s in Minecraft and
* sends input events from Minecraft back to Cacao objects.
*
* @author shadowfacts
*/
2021-02-28 02:48:40 +00:00
open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title), AbstractCacaoScreen {
2021-02-19 04:12:43 +00:00
// _windows is the internal, mutable object, since we only want it to by mutated by the add/removeWindow methods.
private val _windows = LinkedList<Window>()
/**
* The list of windows that belong to this screen.
2021-02-28 17:19:09 +00:00
*
* The window at the end of this list is the active window is the only window that will receive input events.
*
2021-02-19 04:12:43 +00:00
* This list should never be modified directly, only by using the [addWindow]/[removeWindow] methods.
*/
2021-02-19 04:27:18 +00:00
override val windows: List<Window> = _windows
2021-02-19 04:12:43 +00:00
private var hasAppeared = false
2021-02-19 04:12:43 +00:00
/**
2021-02-28 17:19:09 +00:00
* Adds the given window to this screen's window list at the given position.
2021-02-19 04:12:43 +00:00
*
* @param window The Window to add to this screen.
* @param index The index to insert the window into the window list at.
* @return The window that was added, as a convenience.
*/
2021-02-19 04:27:18 +00:00
override fun <T: Window> addWindow(window: T, index: Int): T {
if (hasAppeared) {
window.viewController.viewWillAppear()
}
2021-02-19 04:12:43 +00:00
_windows.add(index, window)
window.screen = this
window.wasAdded()
window.resize(width, height)
return window
}
2021-02-28 17:19:09 +00:00
/**
* Adds the given window to the end of this screen's window list, making it the active window.
*/
2021-02-19 04:27:18 +00:00
override fun <T : Window> addWindow(window: T): T {
return addWindow(window, _windows.size)
}
2021-02-19 04:12:43 +00:00
/**
* Removes the given window from this screen's window list.
*/
2021-02-19 04:27:18 +00:00
override fun removeWindow(window: Window) {
2021-02-19 04:12:43 +00:00
_windows.remove(window)
if (windows.isEmpty()) {
2022-06-16 14:45:32 +00:00
close()
}
2021-02-19 04:12:43 +00:00
}
override fun screenWillAppear() {
windows.forEach {
it.viewController.viewWillAppear()
}
}
override fun init() {
super.init()
2021-02-19 04:12:43 +00:00
windows.forEach {
it.resize(width, height)
}
}
2022-06-16 14:45:32 +00:00
override fun close() {
super.close()
2021-02-27 19:02:30 +00:00
windows.forEach {
it.viewController.viewWillDisappear()
it.viewController.viewDidDisappear()
2021-02-27 19:02:30 +00:00
// resign the current first responder (if any)
it.firstResponder = null
}
}
2021-02-19 04:12:43 +00:00
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
if (client != null) {
// workaround this.minecraft sometimes being null causing a crash
renderBackground(matrixStack)
}
val mouse = Point(mouseX, mouseY)
windows.forEach {
it.draw(matrixStack, mouse, delta)
}
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
val window = windows.lastOrNull()
val result = window?.mouseClicked(Point(mouseX, mouseY), MouseButton.fromMC(button))
return if (result == true) {
RenderHelper.playSound(SoundEvents.UI_BUTTON_CLICK)
true
} else {
false
}
}
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
}
2021-03-20 18:48:59 +00:00
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
val window = windows.lastOrNull()
val result = window?.mouseScrolled(Point(mouseX, mouseY), amount)
return result == true
}
2021-02-27 19:02:30 +00:00
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
windows.lastOrNull()?.removeFromScreen()
2021-02-27 19:02:30 +00:00
return true
} else {
val modifiersSet by lazy { KeyModifiers(modifiers) }
if (findResponder { it.keyPressed(keyCode, modifiersSet) }) {
return true
}
return super.keyPressed(keyCode, scanCode, modifiers)
2021-02-27 19:02:30 +00:00
}
}
override fun keyReleased(i: Int, j: Int, k: Int): Boolean {
return super.keyReleased(i, j, k)
}
override fun charTyped(char: Char, modifiers: Int): Boolean {
val modifiersSet by lazy { KeyModifiers(modifiers) }
if (findResponder { it.charTyped(char, modifiersSet) }) {
return true
}
return super.charTyped(char, modifiers)
}
override fun shouldCloseOnEsc(): Boolean {
return false
}
2021-03-03 03:20:25 +00:00
}
fun AbstractCacaoScreen.findResponder(fn: (Responder) -> Boolean): Boolean {
var responder = windows.lastOrNull()?.firstResponder
while (responder != null) {
if (fn(responder)) {
return true
2021-02-27 19:02:30 +00:00
}
2021-03-03 03:20:25 +00:00
responder = responder.nextResponder
2021-02-27 19:02:30 +00:00
}
2021-03-03 03:20:25 +00:00
return false
2021-02-28 02:48:40 +00:00
}