Use CopyOnWrite for panel lists, update panel isHovered to be more reliable, fix FoldableSlotPanel
This commit is contained in:
parent
d7b7ab9a67
commit
aa461c322f
@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.client.screen
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.gui.Font
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@ -54,8 +53,7 @@ import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayDeque
|
||||
import kotlin.collections.ArrayList
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.MutableSet
|
||||
import kotlin.collections.isNotEmpty
|
||||
@ -73,7 +71,8 @@ import kotlin.collections.withIndex
|
||||
abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, title: Component) : AbstractContainerScreen<T>(menu, inventory, title) {
|
||||
constructor(menu: T, title: Component) : this(menu, menu.inventory, title)
|
||||
|
||||
protected val panels = ArrayDeque<EditablePanel<*>>()
|
||||
protected val panels = CopyOnWriteArrayList<EditablePanel<*>>()
|
||||
protected val panelsReversed = panels.asReversed()
|
||||
val panelsView: List<EditablePanel<*>> = Collections.unmodifiableList(panels)
|
||||
|
||||
var inventoryFrame: FramePanel<MatteryScreen<*>>? = null
|
||||
@ -473,7 +472,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
|
||||
override fun onClose() {
|
||||
super.onClose()
|
||||
ObjectArrayList(panels).forEach { it.markRemoved() }
|
||||
panels.forEach { it.markRemoved() }
|
||||
}
|
||||
|
||||
public override fun recalculateQuickCraftRemaining() {
|
||||
@ -508,7 +507,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
var click = false
|
||||
var focusKilled = false
|
||||
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (click || !panel.mouseClickedChecked(x, y, button)) {
|
||||
focusKilled = panel.killFocus() || focusKilled
|
||||
} else {
|
||||
@ -527,7 +526,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
private var lastDragSlot: Slot? = null
|
||||
|
||||
override fun mouseDragged(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.mouseDraggedChecked(x, y, button, xDelta, yDelta)) {
|
||||
if (returnSlot != null) {
|
||||
super.mouseDragged(x, y, button, xDelta, yDelta)
|
||||
@ -555,7 +554,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
}
|
||||
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.mouseReleasedChecked(p_97812_, p_97813_, p_97814_)) {
|
||||
if (returnSlot != null) {
|
||||
super.mouseReleased(p_97812_, p_97813_, p_97814_)
|
||||
@ -571,7 +570,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.mouseScrolledChecked(mouseX, mouseY, scrollY)) {
|
||||
return true
|
||||
}
|
||||
@ -581,7 +580,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
|
||||
override fun keyReleased(p_94715_: Int, p_94716_: Int, p_94717_: Int): Boolean {
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.keyReleased(p_94715_, p_94716_, p_94717_)) {
|
||||
return true
|
||||
}
|
||||
@ -591,7 +590,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
|
||||
override fun charTyped(p_94683_: Char, p_94684_: Int): Boolean {
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.charTyped(p_94683_, p_94684_)) {
|
||||
return true
|
||||
}
|
||||
@ -601,7 +600,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
|
||||
override fun keyPressed(key: Int, scancode: Int, mods: Int): Boolean {
|
||||
for (panel in ObjectArrayList(panels)) {
|
||||
for (panel in panels) {
|
||||
if (panel.keyPressed(key, scancode, mods)) {
|
||||
if (returnSlot != null) {
|
||||
super.keyPressed(key, scancode, mods)
|
||||
@ -662,23 +661,26 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
for (panel in panels) {
|
||||
if (hovered) {
|
||||
panel.unsetHovered()
|
||||
} else if (panel.tickHover(mouseXf, mouseYf)) {
|
||||
} else if (panel.tickHovered0(mouseXf, mouseYf)) {
|
||||
hovered = true
|
||||
}
|
||||
}
|
||||
|
||||
panels.forEach { it.tickHovered1() }
|
||||
panels.forEach { it.tickHovered2() }
|
||||
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.enableDepthTest()
|
||||
|
||||
for (panel in panels.asReversed()) {
|
||||
for (panel in panelsReversed) {
|
||||
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
||||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||
panel.render(wrap, mouseXf, mouseYf, partialTick)
|
||||
}
|
||||
|
||||
if (!panels.asReversed().any { it.updateCursor0() })
|
||||
panels.asReversed().any { it.updateCursor1() }
|
||||
if (!panelsReversed.any { it.updateCursor0() })
|
||||
panelsReversed.any { it.updateCursor1() }
|
||||
|
||||
RenderSystem.depthFunc(GL11.GL_LESS)
|
||||
NeoForge.EVENT_BUS.post(ContainerScreenEvent.Render.Background(this, graphics, mouseX, mouseY))
|
||||
|
@ -13,7 +13,6 @@ import net.minecraft.client.gui.navigation.ScreenRectangle
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.renderer.Rect2i
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.SystemTime
|
||||
import ru.dbotthepony.mc.otm.client.CursorType
|
||||
@ -28,6 +27,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.input.QueryUserPanel
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
||||
import java.util.*
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.function.Predicate
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.roundToInt
|
||||
@ -259,8 +259,8 @@ open class EditablePanel<out S : Screen>(
|
||||
var dockedHeight: Float = 0f
|
||||
private set
|
||||
|
||||
private val childrenInternal = ArrayList<EditablePanel<*>>()
|
||||
private val visibleChildrenInternal = ArrayList<EditablePanel<*>>()
|
||||
private val childrenInternal = CopyOnWriteArrayList<EditablePanel<*>>()
|
||||
private val visibleChildrenInternal = CopyOnWriteArrayList<EditablePanel<*>>()
|
||||
|
||||
val children: List<EditablePanel<*>> = Collections.unmodifiableList(childrenInternal)
|
||||
val visibleChildren: List<EditablePanel<*>> = Collections.unmodifiableList(visibleChildrenInternal)
|
||||
@ -659,47 +659,54 @@ open class EditablePanel<out S : Screen>(
|
||||
var absoluteY = 0f
|
||||
private set
|
||||
|
||||
private var pendingIsHovered = false
|
||||
private set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
pendingIsEffectivelyHovered = value || pendingIsEffectivelyHovered
|
||||
parent?.updateIsEffectivelyHovered(value || pendingIsEffectivelyHovered)
|
||||
}
|
||||
}
|
||||
|
||||
private var pendingIsEffectivelyHovered = false
|
||||
private set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
parent?.updateIsEffectivelyHovered(value || pendingIsHovered)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this exact panel is hovered. Panel is not considered hovered if any of its children are hovered
|
||||
*/
|
||||
var isHovered = false
|
||||
private set(value) {
|
||||
if (value == field) {
|
||||
return
|
||||
}
|
||||
|
||||
val old = field
|
||||
field = value
|
||||
|
||||
onHoverUpdate(old, value)
|
||||
}
|
||||
private set
|
||||
|
||||
/**
|
||||
* If this panel or any of its children are hovered
|
||||
*/
|
||||
val isEverHovered: Boolean get() {
|
||||
return isHovered || visibleChildrenInternal.any { it.isEverHovered }
|
||||
var isEffectivelyHovered: Boolean = false
|
||||
private set
|
||||
|
||||
private fun updateIsEffectivelyHovered(childrenState: Boolean) {
|
||||
pendingIsEffectivelyHovered = pendingIsHovered || childrenState || visibleChildrenInternal.any { it.pendingIsEffectivelyHovered }
|
||||
}
|
||||
|
||||
fun unsetHovered() {
|
||||
isHovered = false
|
||||
pendingIsHovered = false
|
||||
pendingIsEffectivelyHovered = false
|
||||
|
||||
for (child in childrenInternal) {
|
||||
child.unsetHovered()
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onHoverUpdate(oldHover: Boolean, newHover: Boolean) {
|
||||
if (newHover) {
|
||||
onHovered()
|
||||
} else {
|
||||
onUnHovered()
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onHovered() {}
|
||||
protected open fun onUnHovered() {}
|
||||
|
||||
protected open fun onEffectivelyHovered() {}
|
||||
protected open fun onEffectivelyUnHovered() {}
|
||||
|
||||
var hasFocusedChildren = false
|
||||
private set(value) {
|
||||
if (field != value) {
|
||||
@ -746,6 +753,7 @@ open class EditablePanel<out S : Screen>(
|
||||
|
||||
if (child.visible) {
|
||||
visibleChildrenInternal.add(child)
|
||||
updateIsEffectivelyHovered(false)
|
||||
layoutInvalidated = true
|
||||
}
|
||||
|
||||
@ -793,7 +801,7 @@ open class EditablePanel<out S : Screen>(
|
||||
}
|
||||
|
||||
protected open fun shouldRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
||||
return isEverHovered || isGrabbingMouseInput()
|
||||
return isEffectivelyHovered || isGrabbingMouseInput()
|
||||
}
|
||||
|
||||
fun isVisible(): Boolean {
|
||||
@ -934,7 +942,10 @@ open class EditablePanel<out S : Screen>(
|
||||
}
|
||||
}
|
||||
|
||||
fun tickHover(mouseX: Float, mouseY: Float): Boolean {
|
||||
/**
|
||||
* Determining whenever panel is hovered or not
|
||||
*/
|
||||
fun tickHovered0(mouseX: Float, mouseY: Float): Boolean {
|
||||
if (isRemoved)
|
||||
return false
|
||||
|
||||
@ -957,23 +968,69 @@ open class EditablePanel<out S : Screen>(
|
||||
for (child in visibleChildrenInternal) {
|
||||
if (hit) {
|
||||
child.unsetHovered()
|
||||
} else if (child.tickHover(mouseX, mouseY)) {
|
||||
} else if (child.tickHovered0(mouseX, mouseY)) {
|
||||
hit = true
|
||||
}
|
||||
}
|
||||
|
||||
isHovered =
|
||||
pendingIsHovered =
|
||||
!hit &&
|
||||
mouseX in absoluteX ..< absoluteX + width &&
|
||||
mouseY in absoluteY ..< absoluteY + height
|
||||
|
||||
return hit || isHovered
|
||||
return hit || pendingIsHovered
|
||||
} else {
|
||||
unsetHovered()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private var needToCallIsHoveredUpdate = false
|
||||
private var needToCallIsEffectivelyHoveredUpdate = false
|
||||
|
||||
/**
|
||||
* Updating publicly-visible flags regarding hovered
|
||||
*/
|
||||
fun tickHovered1() {
|
||||
if (isRemoved)
|
||||
return
|
||||
|
||||
needToCallIsHoveredUpdate = isHovered != pendingIsHovered
|
||||
needToCallIsEffectivelyHoveredUpdate = isEffectivelyHovered != pendingIsEffectivelyHovered
|
||||
|
||||
isHovered = pendingIsHovered
|
||||
isEffectivelyHovered = pendingIsEffectivelyHovered
|
||||
|
||||
visibleChildrenInternal.forEach { it.tickHovered1() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatching "is hovered" update callbacks
|
||||
*/
|
||||
fun tickHovered2() {
|
||||
if (needToCallIsHoveredUpdate) {
|
||||
if (isHovered) {
|
||||
onHovered()
|
||||
} else {
|
||||
onUnHovered()
|
||||
}
|
||||
|
||||
needToCallIsHoveredUpdate = false
|
||||
}
|
||||
|
||||
if (needToCallIsEffectivelyHoveredUpdate) {
|
||||
if (isEffectivelyHovered) {
|
||||
onEffectivelyHovered()
|
||||
} else {
|
||||
onEffectivelyUnHovered()
|
||||
}
|
||||
|
||||
needToCallIsEffectivelyHoveredUpdate = false
|
||||
}
|
||||
|
||||
visibleChildrenInternal.forEach { it.tickHovered2() }
|
||||
}
|
||||
|
||||
data class PanelOfTypeResult<T>(val panel: T?, val interrupt: Boolean) {
|
||||
constructor(panel: T) : this(panel, true)
|
||||
|
||||
@ -1765,7 +1822,7 @@ open class EditablePanel<out S : Screen>(
|
||||
|
||||
tickInner()
|
||||
|
||||
for (child in Array(visibleChildrenInternal.size) { visibleChildrenInternal[it] }) {
|
||||
for (child in visibleChildrenInternal) {
|
||||
child.tick()
|
||||
}
|
||||
}
|
||||
@ -1796,7 +1853,7 @@ open class EditablePanel<out S : Screen>(
|
||||
screen.removePanel(this as EditablePanel<MatteryScreen<*>>)
|
||||
}
|
||||
|
||||
for (child in Array(childrenInternal.size) { childrenInternal[it] }) {
|
||||
for (child in childrenInternal) {
|
||||
child.remove()
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,9 @@ class Panel2Widget<out S: Screen, out P : EditablePanel<S>>(
|
||||
|
||||
val wrap = MGUIGraphics(graphics)
|
||||
|
||||
panel.tickHover(xFloat, yFloat)
|
||||
panel.tickHovered0(xFloat, yFloat)
|
||||
panel.tickHovered1()
|
||||
panel.tickHovered2()
|
||||
panel.render(wrap, xFloat, yFloat, partialTick)
|
||||
panel.renderTooltips(wrap, xFloat, yFloat, partialTick)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ open class FoldableSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
||||
this@FoldableSlotPanel.hoverPanel = null
|
||||
}
|
||||
|
||||
override fun onUnHovered() {
|
||||
override fun onEffectivelyUnHovered() {
|
||||
remove()
|
||||
}
|
||||
|
||||
@ -76,11 +76,11 @@ open class FoldableSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
||||
var hoverPanel: FoldableSlotPanel<*, *>.HoverPanel? = null
|
||||
protected set
|
||||
|
||||
override fun onHovered() {
|
||||
override fun onEffectivelyHovered() {
|
||||
hoveringSince = SystemTime()
|
||||
}
|
||||
|
||||
override fun onUnHovered() {
|
||||
override fun onEffectivelyUnHovered() {
|
||||
hoveringSince = null
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user