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) { for (panel in panels) {
if (click || !panel.mouseClickedChecked(x, y, button)) { if (click || !panel.mouseClickedChecked(x, y, button)) {
focusKilled = panel.killFocusForEverythingExceptInner() || focusKilled focusKilled = panel.killFocus() || focusKilled
} else { } else {
if (returnSlot != null) { if (returnSlot != null) {
super.mouseClicked(x, y, button) 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 onHovered() {}
protected open fun onUnHovered() {} protected open fun onUnHovered() {}
var isFocused = false var hasFocusedChildren = false
set(value) { private set(value) {
if (field != value) { if (field != value) {
val old = field
field = value field = value
onHierarchicalFocusChanged()
onFocusChanged(value, old)
findAbsoluteRoot().updateFocus()
} }
} }
var autoKillFocus = true var isFocusedThis = false
private var focusedAsParent = 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 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 { private fun killGrabMouseInput() {
var status = false
for (child in childrenInternal) { for (child in childrenInternal) {
status = child.killFocusInternal() || status child.killGrabMouseInput()
} }
if (isFocused) { grabMouseInput = false
isFocused = false }
private fun killFocusThis(children: Boolean): Boolean {
var status = false
if (isFocusedThis) {
isFocusedThis = false
status = true
}
if (children && hasFocusedChildren) {
hasFocusedChildren = false
status = true status = true
} }
@ -1125,29 +1138,19 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return status return status
} }
private fun killGrabMouseInput() {
for (child in childrenInternal) {
child.killGrabMouseInput()
}
grabMouseInput = false
}
fun killFocus(): Boolean { fun killFocus(): Boolean {
if (isEverFocused()) { var status = false
val status = killFocusInternal() status = killFocusThis(true) || status
findAbsoluteRoot().updateFocus()
return status for (child in childrenInternal) {
} else if (isGrabbingMouseInput()) { status = child.killFocus() || status
killGrabMouseInput()
return true
} }
return false return status
} }
fun findHierarchicalFocus(): EditablePanel<*>? { fun findHierarchicalFocus(): EditablePanel<*>? {
if (isFocused) { if (isFocusedThis) {
return this return this
} }
@ -1166,46 +1169,35 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return findHierarchicalFocus() != null return findHierarchicalFocus() != null
} }
protected open fun onHierarchicalFocusChanged(new: Boolean, old: Boolean) { protected open fun onHierarchicalFocusChanged() {}
protected open fun onFocusChanged() {}
}
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()
}
}
fun isEverFocused(): Boolean { fun isEverFocused(): Boolean {
return isFocused || focusedAsParent return isFocusedThis || hasFocusedChildren
} }
fun requestFocus() { fun requestFocus() {
if (isFocused) { if (isFocusedThis || !isVisible()) {
return return
} }
if (focusedAsParent) { var filter: EditablePanel<*>? = null
var child = findHierarchicalFocus() var parent: EditablePanel<*>? = this
while (child != null) { while (parent != null) {
child.isFocused = false for (child in parent.childrenInternal) {
child = findHierarchicalFocus() if (child !== filter) {
child.killFocus()
}
} }
filter = parent
parent = parent.parent
parent?.killFocusThis(false)
parent?.hasFocusedChildren = true
} }
isFocused = true isFocusedThis = true
} }
protected open fun xPosUpdated(new: Float, old: Float) {} 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 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 { final override fun mouseClicked(x: Double, y: Double, button: Int): Boolean {
if (!isVisible() || !acceptMouseInput) return false if (!isVisible() || !acceptMouseInput) return false
if (flashAnyBlocker()) return true 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) { for (child in visibleChildrenInternal) {
if (child.isGrabbingMouseInput() && child.mouseClickedChecked(x, y, button)) { if (child.isGrabbingMouseInput() && child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true return true
} }
} }
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
if (child.mouseClickedChecked(x, y, button)) { if (child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true 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 { fun mouseClickedChecked(x: Double, y: Double, button: Int): Boolean {
if (!isVisible() || !acceptMouseInput) return false if (!isVisible() || !acceptMouseInput) return false
if (isGrabbingMouseInput() || withinBounds(x, y)) { if (isGrabbingMouseInput() || withinBounds(x, y)) {
popup()
return mouseClicked(x, y, button) return mouseClicked(x, y, button)
} else if (withinExtendedBounds(x, y)) { } else if (withinExtendedBounds(x, y)) {
popup(false) popup(false)
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
if (child.mouseClickedChecked(x, y, button)) { if (child.mouseClickedChecked(x, y, button)) {
killFocusForEverythingExcept(child)
return true return true
} }
} }
if (autoKillFocus) killFocus()
} else if (autoKillFocus) {
killFocus()
} }
return false 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 { final override fun keyPressed(key: Int, scancode: Int, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false if (!isEverFocused()) return false
if (flashAnyBlocker(true)) return true
if (flashAnyBlocker(true)) { if (isFocusedThis) return keyPressedInternal(key, scancode, mods)
return true
}
if (isFocused) return keyPressedInternal(key, scancode, mods)
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
if (child.keyPressed(key, scancode, mods)) { 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 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 { final override fun keyReleased(key: Int, scancode: Int, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false if (!isEverFocused()) return false
if (flashAnyBlocker(false)) return true
if (flashAnyBlocker(false)) { if (isFocusedThis) return keyReleasedInternal(key, scancode, mods)
return true
}
if (isFocused) return keyReleasedInternal(key, scancode, mods)
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
if (child.keyReleased(key, scancode, mods)) { 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 return false
} }
@ -1557,13 +1524,9 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
final override fun charTyped(codepoint: Char, mods: Int): Boolean { final override fun charTyped(codepoint: Char, mods: Int): Boolean {
if (!isVisible() || !acceptKeyboardInput) return false if (!isVisible() || !acceptKeyboardInput) return false
if (!focusedAsParent) return false if (!isEverFocused()) return false
if (flashAnyBlocker(false)) return true
if (flashAnyBlocker()) { if (isFocusedThis) return charTypedInternal(codepoint, mods)
return true
}
if (isFocused) return charTypedInternal(codepoint, mods)
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
if (child.charTyped(codepoint, mods)) { 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 return true
} }
@ -1638,7 +1602,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
screen.popup(this as EditablePanel<MatteryScreen<*>>) screen.popup(this as EditablePanel<MatteryScreen<*>>)
} }
if (focus && !isEverFocused()) { if (focus) {
requestFocus() requestFocus()
} }
} }

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.client.screen.panels.input 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.components.EditBox
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -23,15 +24,11 @@ open class EditBoxPanel<out S : Screen>(
} }
override fun isFocused(): Boolean { override fun isFocused(): Boolean {
return this@EditBoxPanel.isFocused return this@EditBoxPanel.isFocusedThis
} }
} }
} }
init {
autoKillFocus = true
}
override fun copyValues(new_widget: EditBox, old_widget: EditBox) { override fun copyValues(new_widget: EditBox, old_widget: EditBox) {
new_widget.value = old_widget.value new_widget.value = old_widget.value
} }
@ -42,11 +39,11 @@ open class EditBoxPanel<out S : Screen>(
} }
override fun configureNew(widget: EditBox, recreation: Boolean) { override fun configureNew(widget: EditBox, recreation: Boolean) {
widget.setFocus(isFocused) widget.setFocus(isFocusedThis)
} }
override fun onFocusChanged(new: Boolean, old: Boolean) { override fun onFocusChanged() {
widget?.setFocus(new) widget?.setFocus(isFocusedThis)
} }
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
@ -54,4 +51,13 @@ open class EditBoxPanel<out S : Screen>(
requestFocus() requestFocus()
return true 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() { override fun tickInner() {
super.tickInner() super.tickInner()
if (isFocused) { if (isFocusedThis) {
if (!isAvailable.asBoolean) { if (!isAvailable.asBoolean) {
killFocus() killFocus()
return return

View File

@ -19,10 +19,10 @@ open class NetworkedStringInputPanel<out S : Screen>(
get() = backend.test(minecraft.player) get() = backend.test(minecraft.player)
set(value) {} set(value) {}
override fun onFocusChanged(new: Boolean, old: Boolean) { override fun onFocusChanged() {
super.onFocusChanged(new, old) super.onFocusChanged()
if (new && !backend.test(minecraft.player)) { if (isFocusedThis && !backend.test(minecraft.player)) {
killFocus() 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.addAll
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.milliTime
import kotlin.math.roundToInt
open class TextInputPanel<out S : Screen>( open class TextInputPanel<out S : Screen>(
screen: S, screen: S,
@ -149,7 +148,6 @@ open class TextInputPanel<out S : Screen>(
init { init {
scissor = true scissor = true
dockPadding = DockProperty(2f, 2f, 2f, 2f) dockPadding = DockProperty(2f, 2f, 2f, 2f)
autoKillFocus = true
} }
private var oldText = ArrayList<String>() private var oldText = ArrayList<String>()
@ -1138,7 +1136,7 @@ open class TextInputPanel<out S : Screen>(
break break
} }
if (isFocused && milliTime % 1000L > 500L) { if (isFocusedThis && milliTime % 1000L > 500L) {
val activeLine = this[cursorLine] val activeLine = this[cursorLine]
if (activeLine == null || cursorRow >= activeLine.length) { if (activeLine == null || cursorRow >= activeLine.length) {