diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreen.kt b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreen.kt index c4fb999..f6a23e5 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreen.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreen.kt @@ -17,6 +17,7 @@ import net.minecraft.text.LiteralText import net.minecraft.text.Text import net.minecraft.text.TranslatableText import net.minecraft.util.Identifier +import net.minecraft.util.math.MathHelper import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.networking.C2STerminalRequestItem import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems @@ -28,6 +29,7 @@ import java.lang.NumberFormatException import kotlin.math.ceil import kotlin.math.floor import kotlin.math.min +import kotlin.math.roundToInt /** * @author shadowfacts @@ -59,6 +61,15 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, } private var dialogChildren = mutableListOf() + 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 dialogHeight = 62 @@ -150,7 +161,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, private fun requestUpdatedItems() { 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() { @@ -176,6 +187,9 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, val x = (width - backgroundWidth) / 2 val y = (height - backgroundHeight) / 2 drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight) + + // scroll thumb + drawTexture(matrixStack, x + 232, y + scrollThumbTop, 52, 230, thumbWidth, thumbHeight) } @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()) } + 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?) { super.onMouseClick(slot, invSlot, clickData, type) @@ -261,15 +285,25 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, } return false } else { + if (isPointInsScrollThumb(mouseX, mouseY)) { + isDraggingScrollThumb = true + return true + } + 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) { return false + } else if (isDraggingScrollThumb) { + scrollPosition = (mouseY.toFloat() - (y + trackMinY) - 7.5f) / (trackHeight - 15) + scrollPosition = MathHelper.clamp(scrollPosition, 0f, 1f) + requestUpdatedItems() + return true } 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) { return false } else { + isDraggingScrollThumb = false + 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) { return false } 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 if (searchBox.charTyped(c, i)) { if (searchBox.text != oldText) { + scrollPosition = 0f requestUpdatedItems() } return true @@ -331,6 +374,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, val oldText = searchBox.text if (searchBox.keyPressed(key, j, k)) { if (searchBox.text != oldText) { + scrollPosition = 0f requestUpdatedItems() } return true diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreenHandler.kt b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreenHandler.kt index 25d4f5b..5137ad9 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreenHandler.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalScreenHandler.kt @@ -17,7 +17,10 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.copyWithCount import java.lang.ref.WeakReference +import kotlin.math.ceil +import kotlin.math.max import kotlin.math.min +import kotlin.math.roundToInt /** * @author shadowfacts @@ -29,10 +32,15 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter val ID = Identifier(PhysicalConnectivity.MODID, "terminal") } + private val rowsDisplayed = 6 + private val fakeInv = FakeInventory(this) private var searchQuery: String = "" var sortMode = SortMode.COUNT_HIGH_FIRST private set + var totalEntries = 0 + private set + private var scrollPosition = 0f private var itemEntries = listOf() set(value) { field = value @@ -96,6 +104,8 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter it.key.name.string.contains(searchQuery, true) } + totalEntries = filtered.size + val sorted = when (sortMode) { 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 } } - 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.sortMode = sortMode + this.scrollPosition = scrollPosition netItemsChanged() } - fun receivedUpdatedItemsFromServer(entries: List, query: String, sortMode: SortMode) { + fun receivedUpdatedItemsFromServer(entries: List, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int) { assert(playerInv.player.world.isClient) this.searchQuery = query this.sortMode = sortMode + this.scrollPosition = scrollPosition + this.totalEntries = totalEntries itemEntries = entries } diff --git a/src/main/kotlin/net/shadowfacts/phycon/networking/C2STerminalUpdateDisplayedItems.kt b/src/main/kotlin/net/shadowfacts/phycon/networking/C2STerminalUpdateDisplayedItems.kt index f080066..c27da55 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/networking/C2STerminalUpdateDisplayedItems.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/networking/C2STerminalUpdateDisplayedItems.kt @@ -21,7 +21,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver { 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() buf.writeIdentifier(terminal.world!!.registryKey.value) @@ -29,6 +29,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver { buf.writeString(query) buf.writeVarInt(sortMode.ordinal) + buf.writeFloat(scrollPosition) return ClientPlayNetworking.createC2SPacket(CHANNEL, buf) } @@ -38,13 +39,14 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver { val pos = buf.readBlockPos() val query = buf.readString() val sortMode = SortMode.values()[buf.readVarInt()] + val scrollPosition = buf.readFloat() server.execute { if (player.world.registryKey.value != dimID) return@execute val screenHandler = player.currentScreenHandler if (screenHandler !is TerminalScreenHandler) return@execute if (screenHandler.terminal.pos != pos) return@execute - screenHandler.sendUpdatedItemsToClient(player, query, sortMode) + screenHandler.sendUpdatedItemsToClient(player, query, sortMode, scrollPosition) } } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/networking/S2CTerminalUpdateDisplayedItems.kt b/src/main/kotlin/net/shadowfacts/phycon/networking/S2CTerminalUpdateDisplayedItems.kt index ccc05a1..042d109 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/networking/S2CTerminalUpdateDisplayedItems.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/networking/S2CTerminalUpdateDisplayedItems.kt @@ -17,7 +17,7 @@ import net.shadowfacts.phycon.util.SortMode object S2CTerminalUpdateDisplayedItems: ClientReceiver { override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL - operator fun invoke(terminal: TerminalBlockEntity, entries: List, query: String, sortMode: SortMode): Packet<*> { + operator fun invoke(terminal: TerminalBlockEntity, entries: List, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int): Packet<*> { val buf = PacketByteBufs.create() buf.writeIdentifier(terminal.world!!.registryKey.value) @@ -31,6 +31,8 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver { buf.writeString(query) buf.writeVarInt(sortMode.ordinal) + buf.writeFloat(scrollPosition) + buf.writeInt(totalEntries) return ServerPlayNetworking.createS2CPacket(CHANNEL, buf) } @@ -45,13 +47,15 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver { } val query = buf.readString() val sortMode = SortMode.values()[buf.readVarInt()] + val scrollPosition = buf.readFloat() + val totalEntries = buf.readInt() client.execute { if (client.player!!.world.registryKey.value != dimID) return@execute val screenHandler = client.player!!.currentScreenHandler if (screenHandler !is TerminalScreenHandler) return@execute if (screenHandler.terminal.pos != pos) return@execute - screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode) + screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode, scrollPosition, totalEntries) } } } diff --git a/src/main/resources/assets/phycon/textures/gui/terminal.png b/src/main/resources/assets/phycon/textures/gui/terminal.png index c2d10a7..cd530d5 100644 Binary files a/src/main/resources/assets/phycon/textures/gui/terminal.png and b/src/main/resources/assets/phycon/textures/gui/terminal.png differ