Fix terminal search field not unfocusing when REI focused

This commit is contained in:
Shadowfacts 2021-12-23 11:36:46 -05:00
parent c5ede3bd62
commit ef9aa9e958
11 changed files with 95 additions and 56 deletions

View File

@ -1,5 +1,7 @@
package net.shadowfacts.phycon.plugin.rei
import dev.architectury.event.EventResult
import dev.architectury.event.events.client.ClientScreenInputEvent
import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.REIRuntime
import me.shedaniel.rei.api.client.plugins.REIClientPlugin
@ -15,15 +17,17 @@ object PhyConPluginClient: ClientModInitializer, REIClientPlugin {
const val MODID = "phycon_rei"
override fun onInitializeClient() {
AbstractTerminalScreen.registerClickHandler { mouseX, mouseY, button ->
REIRuntime.getInstance().searchTextField?.also {
if (it.isFocused) {
this.terminalVC.searchField.resignFirstResponder()
} else {
this.terminalVC.searchField.becomeFirstResponder()
ClientScreenInputEvent.MOUSE_RELEASED_PRE.register { client, screen, mouseX, mouseY, button ->
if (screen is AbstractTerminalScreen<*, *>) {
REIRuntime.getInstance().searchTextField?.also {
if (it.isFocused) {
screen.terminalVC.searchField.resignFirstResponder()
} else {
screen.terminalVC.searchField.becomeFirstResponder()
}
}
}
null
EventResult.pass()
}
}

View File

@ -0,0 +1,28 @@
package net.shadowfacts.phycon.mixin.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.shadowfacts.cacao.AbstractCacaoScreen;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @author shadowfacts
*/
@Mixin(MinecraftClient.class)
public class MixinMinecraftClient {
@Inject(
method = "setScreen(Lnet/minecraft/client/gui/screen/Screen;)V",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", opcode = Opcodes.PUTFIELD, shift = At.Shift.AFTER)
)
private void setScreen(Screen screen, CallbackInfo ci) {
if (screen instanceof AbstractCacaoScreen) {
((AbstractCacaoScreen)screen).screenWillAppear();
}
}
}

View File

@ -14,4 +14,6 @@ interface AbstractCacaoScreen {
fun removeWindow(window: Window)
}
fun screenWillAppear()
}

View File

@ -1,5 +1,6 @@
package net.shadowfacts.cacao
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
@ -29,10 +30,16 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
override val windows: List<Window> = _windows
private var hasAppeared = false
override fun <T: Window> addWindow(window: T, index: Int): T {
if (window is ScreenHandlerWindow && window.screenHandler != handler) {
throw RuntimeException("Adding ScreenHandlerWindow to CacaoHandledScreen with different screen handler is not supported")
}
if (hasAppeared) {
window.viewController.viewWillAppear()
}
_windows.add(index, window)
@ -54,6 +61,12 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
}
}
override fun screenWillAppear() {
windows.forEach {
it.viewController.viewWillAppear()
}
}
override fun init() {
super.init()
@ -66,7 +79,8 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
super.onClose()
windows.forEach {
// todo: VC callbacks
it.viewController.viewWillDisappear()
it.viewController.viewDidDisappear()
it.firstResponder = null
}

View File

@ -1,5 +1,6 @@
package net.shadowfacts.cacao
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.sound.SoundEvents
@ -32,6 +33,8 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
*/
override val windows: List<Window> = _windows
private var hasAppeared = false
/**
* Adds the given window to this screen's window list at the given position.
*
@ -40,6 +43,10 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
* @return The window that was added, as a convenience.
*/
override fun <T: Window> addWindow(window: T, index: Int): T {
if (hasAppeared) {
window.viewController.viewWillAppear()
}
_windows.add(index, window)
window.screen = this
@ -66,8 +73,14 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
}
}
override fun init() {
super.init()
override fun screenWillAppear() {
windows.forEach {
it.viewController.viewWillAppear()
}
}
override fun resize(client: MinecraftClient, width: Int, height: Int) {
super.resize(client, width, height)
windows.forEach {
it.resize(width, height)
@ -78,7 +91,8 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
super.onClose()
windows.forEach {
// todo: VC callbacks
it.viewController.viewWillDisappear()
it.viewController.viewDidDisappear()
// resign the current first responder (if any)
it.firstResponder = null

View File

@ -147,11 +147,6 @@ class TabViewController<T: TabViewController.Tab>(
currentTabController.viewWillAppear()
}
override fun viewDidAppear() {
super.viewDidAppear()
currentTabController.viewDidAppear()
}
override fun viewWillDisappear() {
super.viewWillDisappear()
currentTabController.viewWillDisappear()
@ -225,7 +220,6 @@ class TabViewController<T: TabViewController.Tab>(
embedChild(currentTabController, tabVCContainer)
currentTabController.didMoveTo(this)
currentTabController.viewWillAppear()
currentTabController.viewDidAppear()
onTabChange?.invoke(currentTab)

View File

@ -122,12 +122,12 @@ abstract class ViewController {
children.forEach(ViewController::viewWillAppear)
}
/**
* Called immediately after the VC's view has first been displayed on screen.
*/
open fun viewDidAppear() {
children.forEach(ViewController::viewDidAppear)
}
// /**
// * Called immediately after the VC's view has first been displayed on screen.
// */
// open fun viewDidAppear() {
// children.forEach(ViewController::viewDidAppear)
// }
/**
* Called before the view will disappear from the screen, either because the VC has been removed from it's parent/screen

View File

@ -4,7 +4,6 @@ import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.Element
import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumerProvider
@ -13,7 +12,6 @@ import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.LiteralText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.shadowfacts.cacao.CacaoHandledScreen
@ -23,7 +21,6 @@ import net.shadowfacts.phycon.networking.C2STerminalRequestItem
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
import java.math.RoundingMode
import java.text.DecimalFormat
import java.util.LinkedList
import kotlin.math.ceil
import kotlin.math.min
@ -38,14 +35,6 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
val terminalBackgroundHeight: Int,
): CacaoHandledScreen<T>(handler, playerInv, title) {
companion object {
private val clickHandlers = LinkedList<AbstractTerminalScreen<*, *>.(Double, Double, Int) -> Boolean?>()
fun registerClickHandler(handler: AbstractTerminalScreen<*, *>.(Double, Double, Int) -> Boolean?) {
clickHandlers.add(handler)
}
}
abstract val backgroundTexture: Identifier
val terminalVC: AbstractTerminalViewController<*, *, *>
@ -160,17 +149,6 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
}
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
for (handler in clickHandlers) {
val res = handler(mouseX, mouseY, button)
if (res != null) {
return res
}
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
super.onMouseClick(slot, invSlot, clickData, type)
@ -191,12 +169,11 @@ abstract class AbstractTerminalScreen<BE: AbstractTerminalBlockEntity, T: Abstra
}
}
private val fakeFocusedElement = TextFieldWidget(textRenderer, 0, 0, 0, 0, LiteralText(""))
override fun getFocused(): Element? {
return if (windows.last().firstResponder != null) {
fakeFocusedElement
} else {
null
override fun setFocused(element: Element?) {
super.setFocused(element)
// so that when something else (e.g., REI) steals focus and calls setFocused(null) on us, any first responder resigns
if (element == null) {
windows.last().firstResponder?.resignFirstResponder()
}
}

View File

@ -100,7 +100,6 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
handler = ::searchFieldChanged
drawBackground = false
}
searchField.becomeFirstResponder()
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
@ -137,6 +136,12 @@ abstract class AbstractTerminalViewController<BE: AbstractTerminalBlockEntity, S
}
}
override fun viewWillAppear() {
super.viewWillAppear()
searchField.becomeFirstResponder()
}
private fun searchFieldChanged(field: TextField) {
screen.searchQuery = field.text
screen.requestUpdatedItems()

View File

@ -1,9 +1,10 @@
{
"required": true,
"package": "net.shadowfacts.phycon.mixin.client",
"compatibilityLevel": "JAVA_8",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MixinHandledScreen",
"MixinMinecraftClient",
"TextFieldWidgetAccessor"
],
"injectors": {

View File

@ -1,10 +1,10 @@
{
"required": true,
"package": "net.shadowfacts.phycon.mixin",
"compatibilityLevel": "JAVA_8",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"injectors": {
"defaultRequire": 1
}
}
}