Un-hellish panel focus logic

This commit is contained in:
DBotThePony 2023-03-07 20:41:12 +07:00
parent fda82f3357
commit 986be8fa1a
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 99 additions and 131 deletions

View File

@ -358,7 +358,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
for (panel in panels) {
if (click || !panel.mouseClickedChecked(x, y, button)) {
focusKilled = panel.killFocusForEverythingExceptInner() || focusKilled
focusKilled = panel.killFocus() || focusKilled
} else {
if (returnSlot != null) {
super.mouseClicked(x, y, button)

View File

@ -560,19 +560,23 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
protected open fun onHovered() {}
protected open fun onUnHovered() {}
var isFocused = false
set(value) {
var hasFocusedChildren = false
private set(value) {
if (field != value) {
val old = field
field = value
onFocusChanged(value, old)
findAbsoluteRoot().updateFocus()
onHierarchicalFocusChanged()
}
}
var autoKillFocus = true
private var focusedAsParent = false
var isFocusedThis = false
private set(value) {
if (field != value) {
field = value
onFocusChanged()
}
}
var autoRequestFocus = true
val font: Font get() = if (screen is MatteryScreen<*>) screen.font else minecraft.font
@ -1105,15 +1109,24 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
}
}
private fun killFocusInternal(): Boolean {
var status = false
private fun killGrabMouseInput() {
for (child in childrenInternal) {
status = child.killFocusInternal() || status
child.killGrabMouseInput()
}
if (isFocused) {
isFocused = false
grabMouseInput = false
}
private fun killFocusThis(children: Boolean): Boolean {
var status = false
if (isFocusedThis) {
isFocusedThis = false
status = true
}
if (children && hasFocusedChildren) {
hasFocusedChildren = false
status = true
}
@ -1125,29 +1138,19 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return status
}
private fun killGrabMouseInput() {
for (child in childrenInternal) {
child.killGrabMouseInput()
}
grabMouseInput = false
}
fun killFocus(): Boolean {
if (isEverFocused()) {
val status = killFocusInternal()
findAbsoluteRoot().updateFocus()
return status
} else if (isGrabbingMouseInput()) {
killGrabMouseInput()
return true
var status = false
status = killFocusThis(true) || status
for (child in childrenInternal) {
status = child.killFocus() || status
}
return false
return status
}
fun findHierarchicalFocus(): EditablePanel<*>? {
if (isFocused) {
if (isFocusedThis) {
return this
}
@ -1166,46 +1169,35 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return findHierarchicalFocus() != null
}
protected open fun onHierarchicalFocusChanged(new: Boolean, old: Boolean) {
}
protected open fun onFocusChanged(new: Boolean, old: Boolean) {
}
private fun updateFocus() {
val old = focusedAsParent
focusedAsParent = hasHierarchicalFocus()
if (focusedAsParent != old) {
onHierarchicalFocusChanged(focusedAsParent, old)
}
for (child in childrenInternal) {
child.updateFocus()
}
}
protected open fun onHierarchicalFocusChanged() {}
protected open fun onFocusChanged() {}
fun isEverFocused(): Boolean {
return isFocused || focusedAsParent
return isFocusedThis || hasFocusedChildren
}
fun requestFocus() {
if (isFocused) {
if (isFocusedThis || !isVisible()) {
return
}
if (focusedAsParent) {
var child = findHierarchicalFocus()
var filter: EditablePanel<*>? = null
var parent: EditablePanel<*>? = this
while (child != null) {
child.isFocused = false
child = findHierarchicalFocus()
while (parent != null) {
for (child in parent.childrenInternal) {
if (child !== filter) {
child.killFocus()
}
}
isFocused = true
filter = parent
parent = parent.parent
parent?.killFocusThis(false)
parent?.hasFocusedChildren = true
}
isFocusedThis = true
}
protected open fun xPosUpdated(new: Float, old: Float) {}
@ -1311,69 +1303,52 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
y in pos.y .. pos2.y
}
fun killFocusForEverythingExcept(except: EditablePanel<*>) {
for (child in childrenInternal) {
if (child !== except) {
child.killFocusForEverythingExceptInner()
}
}
}
fun killFocusForEverythingExceptInner(): Boolean {
var focusKilled = false
for (child in childrenInternal) {
focusKilled = child.killFocusForEverythingExceptInner() || focusKilled
}
if (autoKillFocus) {
focusKilled = killFocus() || focusKilled
}
return focusKilled
}
final override fun mouseClicked(x: Double, y: Double, button: Int): Boolean {
if (!isVisible() || !acceptMouseInput) return false
if (flashAnyBlocker()) return true
if (grabMouseInput) return mouseClickedInner(x, y, button)
if (grabMouseInput) {
if (mouseClickedInner(x, y, button)) {
if (autoRequestFocus) requestFocus()
return true
}
return false
}
for (child in visibleChildrenInternal) {
if (child.isGrabbingMouseInput() && child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true
}
}
for (child in visibleChildrenInternal) {
if (child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true
}
}
return mouseClickedInner(x, y, button)
if (mouseClickedInner(x, y, button)) {
if (autoRequestFocus) requestFocus()
return true
}
return false
}
fun mouseClickedChecked(x: Double, y: Double, button: Int): Boolean {
if (!isVisible() || !acceptMouseInput) return false
if (isGrabbingMouseInput() || withinBounds(x, y)) {
popup()
return mouseClicked(x, y, button)
} else if (withinExtendedBounds(x, y)) {
popup(false)
for (child in visibleChildrenInternal) {
if (child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true
}
}
if (autoKillFocus) killFocus()
} else if (autoKillFocus) {
killFocus()
}
return false
@ -1509,13 +1484,9 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
final override fun keyPressed(key: Int, scancode: Int, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false
if (flashAnyBlocker(true)) {
return true
}
if (isFocused) return keyPressedInternal(key, scancode, mods)
if (!isEverFocused()) return false
if (flashAnyBlocker(true)) return true
if (isFocusedThis) return keyPressedInternal(key, scancode, mods)
for (child in visibleChildrenInternal) {
if (child.keyPressed(key, scancode, mods)) {
@ -1523,7 +1494,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
}
}
if (focusedAsParent) return keyPressedInternal(key, scancode, mods)
if (hasFocusedChildren) return keyPressedInternal(key, scancode, mods)
return false
}
@ -1533,13 +1504,9 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
final override fun keyReleased(key: Int, scancode: Int, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false
if (flashAnyBlocker(false)) {
return true
}
if (isFocused) return keyReleasedInternal(key, scancode, mods)
if (!isEverFocused()) return false
if (flashAnyBlocker(false)) return true
if (isFocusedThis) return keyReleasedInternal(key, scancode, mods)
for (child in visibleChildrenInternal) {
if (child.keyReleased(key, scancode, mods)) {
@ -1547,7 +1514,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
}
}
if (focusedAsParent) return keyReleasedInternal(key, scancode, mods)
if (hasFocusedChildren) return keyReleasedInternal(key, scancode, mods)
return false
}
@ -1557,13 +1524,9 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
final override fun charTyped(codepoint: Char, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false
if (flashAnyBlocker()) {
return true
}
if (isFocused) return charTypedInternal(codepoint, mods)
if (!isEverFocused()) return false
if (flashAnyBlocker(false)) return true
if (isFocusedThis) return charTypedInternal(codepoint, mods)
for (child in visibleChildrenInternal) {
if (child.charTyped(codepoint, mods)) {
@ -1571,6 +1534,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
}
}
if (hasFocusedChildren) return charTypedInternal(codepoint, mods)
return true
}
@ -1638,7 +1602,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
screen.popup(this as EditablePanel<MatteryScreen<*>>)
}
if (focus && !isEverFocused()) {
if (focus) {
requestFocus()
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.client.screen.panels.input
import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.client.gui.components.EditBox
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
@ -23,15 +24,11 @@ open class EditBoxPanel<out S : Screen>(
}
override fun isFocused(): Boolean {
return this@EditBoxPanel.isFocused
return this@EditBoxPanel.isFocusedThis
}
}
}
init {
autoKillFocus = true
}
override fun copyValues(new_widget: EditBox, old_widget: EditBox) {
new_widget.value = old_widget.value
}
@ -42,11 +39,11 @@ open class EditBoxPanel<out S : Screen>(
}
override fun configureNew(widget: EditBox, recreation: Boolean) {
widget.setFocus(isFocused)
widget.setFocus(isFocusedThis)
}
override fun onFocusChanged(new: Boolean, old: Boolean) {
widget?.setFocus(new)
override fun onFocusChanged() {
widget?.setFocus(isFocusedThis)
}
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
@ -54,4 +51,13 @@ open class EditBoxPanel<out S : Screen>(
requestFocus()
return true
}
override fun keyPressedInternal(key: Int, scancode: Int, mods: Int): Boolean {
if (key == InputConstants.KEY_ESCAPE && widget?.isActive == true) {
widget?.setFocus(false)
return true
}
return super.keyPressedInternal(key, scancode, mods)
}
}

View File

@ -58,7 +58,7 @@ open class NetworkNumberInputPanel<out S : Screen> @JvmOverloads constructor(
override fun tickInner() {
super.tickInner()
if (isFocused) {
if (isFocusedThis) {
if (!isAvailable.asBoolean) {
killFocus()
return

View File

@ -19,10 +19,10 @@ open class NetworkedStringInputPanel<out S : Screen>(
get() = backend.test(minecraft.player)
set(value) {}
override fun onFocusChanged(new: Boolean, old: Boolean) {
super.onFocusChanged(new, old)
override fun onFocusChanged() {
super.onFocusChanged()
if (new && !backend.test(minecraft.player)) {
if (isFocusedThis && !backend.test(minecraft.player)) {
killFocus()
}
}

View File

@ -27,7 +27,6 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.milliTime
import kotlin.math.roundToInt
open class TextInputPanel<out S : Screen>(
screen: S,
@ -149,7 +148,6 @@ open class TextInputPanel<out S : Screen>(
init {
scissor = true
dockPadding = DockProperty(2f, 2f, 2f, 2f)
autoKillFocus = true
}
private var oldText = ArrayList<String>()
@ -1138,7 +1136,7 @@ open class TextInputPanel<out S : Screen>(
break
}
if (isFocused && milliTime % 1000L > 500L) {
if (isFocusedThis && milliTime % 1000L > 500L) {
val activeLine = this[cursorLine]
if (activeLine == null || cursorRow >= activeLine.length) {