Add Terminal GUI scrolling
This commit is contained in:
parent
6e4d1e63a9
commit
8100532678
|
@ -17,6 +17,7 @@ import net.minecraft.text.LiteralText
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
import net.minecraft.util.math.MathHelper
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.networking.C2STerminalRequestItem
|
import net.shadowfacts.phycon.networking.C2STerminalRequestItem
|
||||||
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
|
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
|
||||||
|
@ -28,6 +29,7 @@ import java.lang.NumberFormatException
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -59,6 +61,15 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
}
|
}
|
||||||
private var dialogChildren = mutableListOf<AbstractButtonWidget>()
|
private var dialogChildren = mutableListOf<AbstractButtonWidget>()
|
||||||
|
|
||||||
|
private var scrollPosition = 0f
|
||||||
|
private var isDraggingScrollThumb = false
|
||||||
|
private val trackMinY = 18
|
||||||
|
private val trackHeight = 106
|
||||||
|
private val thumbHeight = 15
|
||||||
|
private val thumbWidth = 12
|
||||||
|
private val scrollThumbTop: Int
|
||||||
|
get() = trackMinY + (scrollPosition * (trackHeight - thumbHeight)).roundToInt()
|
||||||
|
|
||||||
private val dialogWidth = 158
|
private val dialogWidth = 158
|
||||||
private val dialogHeight = 62
|
private val dialogHeight = 62
|
||||||
|
|
||||||
|
@ -150,7 +161,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
|
|
||||||
private fun requestUpdatedItems() {
|
private fun requestUpdatedItems() {
|
||||||
val player = MinecraftClient.getInstance().player!!
|
val player = MinecraftClient.getInstance().player!!
|
||||||
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchBox.text, sortButton.mode))
|
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchBox.text, sortButton.mode, scrollPosition))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
|
@ -176,6 +187,9 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
val x = (width - backgroundWidth) / 2
|
val x = (width - backgroundWidth) / 2
|
||||||
val y = (height - backgroundHeight) / 2
|
val y = (height - backgroundHeight) / 2
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||||
|
|
||||||
|
// scroll thumb
|
||||||
|
drawTexture(matrixStack, x + 232, y + scrollThumbTop, 52, 230, thumbWidth, thumbHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
|
@ -227,6 +241,16 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
|
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isPointInsScrollThumb(mouseX: Double, mouseY: Double): Boolean {
|
||||||
|
val x = (width - backgroundWidth) / 2
|
||||||
|
val y = (height - backgroundHeight) / 2
|
||||||
|
val thumbMinX = x + 232
|
||||||
|
val thumbMaxX = thumbMinX + thumbWidth
|
||||||
|
val thumbMinY = y + scrollThumbTop
|
||||||
|
val thumbMaxY = thumbMinY + thumbHeight
|
||||||
|
return mouseX >= thumbMinX && mouseX < thumbMaxX && mouseY >= thumbMinY && mouseY < thumbMaxY
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
|
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
|
||||||
super.onMouseClick(slot, invSlot, clickData, type)
|
super.onMouseClick(slot, invSlot, clickData, type)
|
||||||
|
|
||||||
|
@ -261,15 +285,25 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
if (isPointInsScrollThumb(mouseX, mouseY)) {
|
||||||
|
isDraggingScrollThumb = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return super.mouseClicked(mouseX, mouseY, button)
|
return super.mouseClicked(mouseX, mouseY, button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
|
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
|
||||||
if (showingAmountDialog) {
|
if (showingAmountDialog) {
|
||||||
return false
|
return false
|
||||||
|
} else if (isDraggingScrollThumb) {
|
||||||
|
scrollPosition = (mouseY.toFloat() - (y + trackMinY) - 7.5f) / (trackHeight - 15)
|
||||||
|
scrollPosition = MathHelper.clamp(scrollPosition, 0f, 1f)
|
||||||
|
requestUpdatedItems()
|
||||||
|
return true
|
||||||
} else {
|
} else {
|
||||||
return super.mouseDragged(d, e, i, f, g)
|
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,15 +318,23 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
if (showingAmountDialog) {
|
if (showingAmountDialog) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
isDraggingScrollThumb = false
|
||||||
|
|
||||||
return super.mouseReleased(d, e, i)
|
return super.mouseReleased(d, e, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mouseScrolled(d: Double, e: Double, f: Double): Boolean {
|
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
|
||||||
if (showingAmountDialog) {
|
if (showingAmountDialog) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return super.mouseScrolled(d, e, f)
|
var newOffsetInRows = handler.currentScrollOffsetInRows() - amount.toInt()
|
||||||
|
newOffsetInRows = MathHelper.clamp(newOffsetInRows, 0, handler.maxScrollOffsetInRows())
|
||||||
|
val newScrollPosition = newOffsetInRows / handler.maxScrollOffsetInRows().toFloat()
|
||||||
|
scrollPosition = newScrollPosition
|
||||||
|
requestUpdatedItems()
|
||||||
|
|
||||||
|
return super.mouseScrolled(mouseX, mouseY, amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,6 +345,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
val oldText = searchBox.text
|
val oldText = searchBox.text
|
||||||
if (searchBox.charTyped(c, i)) {
|
if (searchBox.charTyped(c, i)) {
|
||||||
if (searchBox.text != oldText) {
|
if (searchBox.text != oldText) {
|
||||||
|
scrollPosition = 0f
|
||||||
requestUpdatedItems()
|
requestUpdatedItems()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -331,6 +374,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
val oldText = searchBox.text
|
val oldText = searchBox.text
|
||||||
if (searchBox.keyPressed(key, j, k)) {
|
if (searchBox.keyPressed(key, j, k)) {
|
||||||
if (searchBox.text != oldText) {
|
if (searchBox.text != oldText) {
|
||||||
|
scrollPosition = 0f
|
||||||
requestUpdatedItems()
|
requestUpdatedItems()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -17,7 +17,10 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||||
import net.shadowfacts.phycon.util.SortMode
|
import net.shadowfacts.phycon.util.SortMode
|
||||||
import net.shadowfacts.phycon.util.copyWithCount
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -29,10 +32,15 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val rowsDisplayed = 6
|
||||||
|
|
||||||
private val fakeInv = FakeInventory(this)
|
private val fakeInv = FakeInventory(this)
|
||||||
private var searchQuery: String = ""
|
private var searchQuery: String = ""
|
||||||
var sortMode = SortMode.COUNT_HIGH_FIRST
|
var sortMode = SortMode.COUNT_HIGH_FIRST
|
||||||
private set
|
private set
|
||||||
|
var totalEntries = 0
|
||||||
|
private set
|
||||||
|
private var scrollPosition = 0f
|
||||||
private var itemEntries = listOf<Entry>()
|
private var itemEntries = listOf<Entry>()
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
|
@ -96,6 +104,8 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
|
||||||
it.key.name.string.contains(searchQuery, true)
|
it.key.name.string.contains(searchQuery, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalEntries = filtered.size
|
||||||
|
|
||||||
val sorted =
|
val sorted =
|
||||||
when (sortMode) {
|
when (sortMode) {
|
||||||
SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue }
|
SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue }
|
||||||
|
@ -103,22 +113,46 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
|
||||||
SortMode.ALPHABETICAL -> filtered.sortedBy { it.key.name.string }
|
SortMode.ALPHABETICAL -> filtered.sortedBy { it.key.name.string }
|
||||||
}
|
}
|
||||||
|
|
||||||
itemEntries = sorted.map { Entry(it.key, it.intValue) }
|
|
||||||
|
|
||||||
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, sortMode))
|
val offsetInItems = currentScrollOffsetInItems()
|
||||||
|
val end = min(offsetInItems + rowsDisplayed * 9, sorted.size)
|
||||||
|
itemEntries = sorted.subList(offsetInItems, end).map { Entry(it.key, it.intValue) }
|
||||||
|
|
||||||
|
// itemEntries = sorted.map { Entry(it.key, it.intValue) }
|
||||||
|
|
||||||
|
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, sortMode, scrollPosition, totalEntries))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, sortMode: SortMode) {
|
fun totalRows(): Int {
|
||||||
|
return ceil(totalEntries / 9f).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun maxScrollOffsetInRows(): Int {
|
||||||
|
return totalRows() - rowsDisplayed
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentScrollOffsetInRows(): Int {
|
||||||
|
return max(0, (scrollPosition * maxScrollOffsetInRows()).roundToInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentScrollOffsetInItems(): Int {
|
||||||
|
return currentScrollOffsetInRows() * 9
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, sortMode: SortMode, scrollPosition: Float) {
|
||||||
this.searchQuery = query
|
this.searchQuery = query
|
||||||
this.sortMode = sortMode
|
this.sortMode = sortMode
|
||||||
|
this.scrollPosition = scrollPosition
|
||||||
netItemsChanged()
|
netItemsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, sortMode: SortMode) {
|
fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int) {
|
||||||
assert(playerInv.player.world.isClient)
|
assert(playerInv.player.world.isClient)
|
||||||
|
|
||||||
this.searchQuery = query
|
this.searchQuery = query
|
||||||
this.sortMode = sortMode
|
this.sortMode = sortMode
|
||||||
|
this.scrollPosition = scrollPosition
|
||||||
|
this.totalEntries = totalEntries
|
||||||
itemEntries = entries
|
itemEntries = entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
|
||||||
|
|
||||||
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_update_displayed")
|
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_update_displayed")
|
||||||
|
|
||||||
operator fun invoke(terminal: TerminalBlockEntity, query: String, sortMode: SortMode): Packet<*> {
|
operator fun invoke(terminal: TerminalBlockEntity, query: String, sortMode: SortMode, scrollPosition: Float): Packet<*> {
|
||||||
val buf = PacketByteBufs.create()
|
val buf = PacketByteBufs.create()
|
||||||
|
|
||||||
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
||||||
|
@ -29,6 +29,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
|
||||||
|
|
||||||
buf.writeString(query)
|
buf.writeString(query)
|
||||||
buf.writeVarInt(sortMode.ordinal)
|
buf.writeVarInt(sortMode.ordinal)
|
||||||
|
buf.writeFloat(scrollPosition)
|
||||||
|
|
||||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||||
}
|
}
|
||||||
|
@ -38,13 +39,14 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
|
||||||
val pos = buf.readBlockPos()
|
val pos = buf.readBlockPos()
|
||||||
val query = buf.readString()
|
val query = buf.readString()
|
||||||
val sortMode = SortMode.values()[buf.readVarInt()]
|
val sortMode = SortMode.values()[buf.readVarInt()]
|
||||||
|
val scrollPosition = buf.readFloat()
|
||||||
|
|
||||||
server.execute {
|
server.execute {
|
||||||
if (player.world.registryKey.value != dimID) return@execute
|
if (player.world.registryKey.value != dimID) return@execute
|
||||||
val screenHandler = player.currentScreenHandler
|
val screenHandler = player.currentScreenHandler
|
||||||
if (screenHandler !is TerminalScreenHandler) return@execute
|
if (screenHandler !is TerminalScreenHandler) return@execute
|
||||||
if (screenHandler.terminal.pos != pos) return@execute
|
if (screenHandler.terminal.pos != pos) return@execute
|
||||||
screenHandler.sendUpdatedItemsToClient(player, query, sortMode)
|
screenHandler.sendUpdatedItemsToClient(player, query, sortMode, scrollPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import net.shadowfacts.phycon.util.SortMode
|
||||||
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
||||||
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
|
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
|
||||||
|
|
||||||
operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.Entry>, query: String, sortMode: SortMode): Packet<*> {
|
operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int): Packet<*> {
|
||||||
val buf = PacketByteBufs.create()
|
val buf = PacketByteBufs.create()
|
||||||
|
|
||||||
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
||||||
|
@ -31,6 +31,8 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
||||||
|
|
||||||
buf.writeString(query)
|
buf.writeString(query)
|
||||||
buf.writeVarInt(sortMode.ordinal)
|
buf.writeVarInt(sortMode.ordinal)
|
||||||
|
buf.writeFloat(scrollPosition)
|
||||||
|
buf.writeInt(totalEntries)
|
||||||
|
|
||||||
return ServerPlayNetworking.createS2CPacket(CHANNEL, buf)
|
return ServerPlayNetworking.createS2CPacket(CHANNEL, buf)
|
||||||
}
|
}
|
||||||
|
@ -45,13 +47,15 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
||||||
}
|
}
|
||||||
val query = buf.readString()
|
val query = buf.readString()
|
||||||
val sortMode = SortMode.values()[buf.readVarInt()]
|
val sortMode = SortMode.values()[buf.readVarInt()]
|
||||||
|
val scrollPosition = buf.readFloat()
|
||||||
|
val totalEntries = buf.readInt()
|
||||||
|
|
||||||
client.execute {
|
client.execute {
|
||||||
if (client.player!!.world.registryKey.value != dimID) return@execute
|
if (client.player!!.world.registryKey.value != dimID) return@execute
|
||||||
val screenHandler = client.player!!.currentScreenHandler
|
val screenHandler = client.player!!.currentScreenHandler
|
||||||
if (screenHandler !is TerminalScreenHandler) return@execute
|
if (screenHandler !is TerminalScreenHandler) return@execute
|
||||||
if (screenHandler.terminal.pos != pos) return@execute
|
if (screenHandler.terminal.pos != pos) return@execute
|
||||||
screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode)
|
screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode, scrollPosition, totalEntries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
Loading…
Reference in New Issue