Convert Terminal screen to Cacao

This commit is contained in:
Shadowfacts 2021-03-20 22:31:53 -04:00
parent 2774cabfcc
commit 84e2c6d6e9
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
15 changed files with 531 additions and 425 deletions

View File

@ -19,8 +19,10 @@ object PhyConPlugin: REIPluginV0 {
override fun registerBounds(helper: DisplayHelper) { override fun registerBounds(helper: DisplayHelper) {
BaseBoundsHandler.getInstance().registerExclusionZones(TerminalScreen::class.java) { BaseBoundsHandler.getInstance().registerExclusionZones(TerminalScreen::class.java) {
val screen = MinecraftClient.getInstance().currentScreen as TerminalScreen val screen = MinecraftClient.getInstance().currentScreen as TerminalScreen
val button = screen.terminalVC.sortMode
val rect = button.convert(button.bounds, to = null)
listOf( listOf(
Rectangle(screen.sortButtonX, screen.sortButtonY, 20, 20) Rectangle(rect.left.toInt(), rect.top.toInt(), 20, 20)
) )
} }
} }

View File

@ -1,5 +1,6 @@
package net.shadowfacts.cacao package net.shadowfacts.cacao
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.util.math.MatrixStack import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
@ -68,7 +69,6 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
} }
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) { override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
renderBackground(matrixStack)
} }
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) { override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
@ -77,15 +77,28 @@ open class CacaoHandledScreen<Handler: ScreenHandler>(
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
val mouse = Point(mouseX, mouseY) val mouse = Point(mouseX, mouseY)
windows.forEachIndexed { index, it ->
RenderSystem.pushMatrix()
RenderSystem.translatef(0f, 0f, -350f)
for (i in windows.indices) {
val it = windows[i]
if (i == windows.size - 1) {
renderBackground(matrixStack)
}
if (it is ScreenHandlerWindow) { if (it is ScreenHandlerWindow) {
if (index == windows.size - 1) { if (i == windows.size - 1) {
super.render(matrixStack, mouseX, mouseY, delta) super.render(matrixStack, mouseX, mouseY, delta)
} else { } else {
// if the screen handler window is not the frontmost, we fake the mouse x/y to disable the slot mouseover effect // if the screen handler window is not the frontmost, we fake the mouse x/y to disable the slot mouseover effect
super.render(matrixStack, -1, -1, delta) super.render(matrixStack, -1, -1, delta)
} }
RenderSystem.popMatrix()
} }
it.draw(matrixStack, mouse, delta) it.draw(matrixStack, mouse, delta)
} }

View File

@ -6,6 +6,7 @@ import net.shadowfacts.cacao.geometry.Rect
import net.shadowfacts.cacao.util.texture.NinePatchTexture import net.shadowfacts.cacao.util.texture.NinePatchTexture
import net.shadowfacts.cacao.util.RenderHelper import net.shadowfacts.cacao.util.RenderHelper
import net.shadowfacts.cacao.util.properties.ResettableLazyProperty import net.shadowfacts.cacao.util.properties.ResettableLazyProperty
import kotlin.math.roundToInt
/** /**
* A helper class for drawing a [NinePatchTexture] in a view. * A helper class for drawing a [NinePatchTexture] in a view.
@ -91,22 +92,22 @@ open class NinePatchView(val ninePatch: NinePatchTexture): View() {
private fun drawEdges(matrixStack: MatrixStack) { private fun drawEdges(matrixStack: MatrixStack) {
// Horizontal // Horizontal
for (i in 0 until (topMiddle.width.toInt() / ninePatch.centerWidth)) { for (i in 0 until (topMiddle.width.roundToInt() / ninePatch.centerWidth)) {
RenderHelper.draw(matrixStack, topMiddle.left + i * ninePatch.centerWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, ninePatch.centerWidth.toDouble(), topMiddle.height, ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, topMiddle.left + i * ninePatch.centerWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, ninePatch.centerWidth.toDouble(), topMiddle.height, ninePatch.texture.width, ninePatch.texture.height)
RenderHelper.draw(matrixStack, bottomMiddle.left + i * ninePatch.centerWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, ninePatch.centerWidth.toDouble(), bottomMiddle.height, ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, bottomMiddle.left + i * ninePatch.centerWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, ninePatch.centerWidth.toDouble(), bottomMiddle.height, ninePatch.texture.width, ninePatch.texture.height)
} }
val remWidth = topMiddle.width.toInt() % ninePatch.centerWidth val remWidth = topMiddle.width.roundToInt() % ninePatch.centerWidth
if (remWidth > 0) { if (remWidth > 0) {
RenderHelper.draw(matrixStack, topMiddle.right - remWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, topMiddle.right - remWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
RenderHelper.draw(matrixStack, bottomMiddle.right - remWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, bottomMiddle.right - remWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
} }
// Vertical // Vertical
for (i in 0 until (leftMiddle.height.toInt() / ninePatch.centerHeight)) { for (i in 0 until (leftMiddle.height.roundToInt() / ninePatch.centerHeight)) {
RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.top + i * ninePatch.centerHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.top + i * ninePatch.centerHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.top + i * ninePatch.centerHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.top + i * ninePatch.centerHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
} }
val remHeight = leftMiddle.height.toInt() % ninePatch.centerHeight val remHeight = leftMiddle.height.roundToInt() % ninePatch.centerHeight
if (remHeight > 0) { if (remHeight > 0) {
RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.bottom - remHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.bottom - remHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.bottom - remHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.bottom - remHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
@ -114,20 +115,20 @@ open class NinePatchView(val ninePatch: NinePatchTexture): View() {
} }
private fun drawCenter(matrixStack: MatrixStack) { private fun drawCenter(matrixStack: MatrixStack) {
for (i in 0 until (center.height.toInt() / ninePatch.centerHeight)) { for (i in 0 until (center.height.roundToInt() / ninePatch.centerHeight)) {
drawCenterRow(matrixStack, center.top + i * ninePatch.centerHeight.toDouble(), ninePatch.centerHeight.toDouble()) drawCenterRow(matrixStack, center.top + i * ninePatch.centerHeight.toDouble(), ninePatch.centerHeight.toDouble())
} }
val remHeight = center.height.toInt() % ninePatch.centerHeight val remHeight = center.height.roundToInt() % ninePatch.centerHeight
if (remHeight > 0) { if (remHeight > 0) {
drawCenterRow(matrixStack, center.bottom - remHeight, remHeight.toDouble()) drawCenterRow(matrixStack, center.bottom - remHeight, remHeight.toDouble())
} }
} }
private fun drawCenterRow(matrixStack: MatrixStack, y: Double, height: Double) { private fun drawCenterRow(matrixStack: MatrixStack, y: Double, height: Double) {
for (i in 0 until (center.width.toInt() / ninePatch.centerWidth)) { for (i in 0 until (center.width.roundToInt() / ninePatch.centerWidth)) {
RenderHelper.draw(matrixStack, center.left + i * ninePatch.centerWidth, y, ninePatch.center.u, ninePatch.center.v, ninePatch.centerWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, center.left + i * ninePatch.centerWidth, y, ninePatch.center.u, ninePatch.center.v, ninePatch.centerWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height)
} }
val remWidth = center.width.toInt() % ninePatch.centerWidth val remWidth = center.width.roundToInt() % ninePatch.centerWidth
if (remWidth > 0) { if (remWidth > 0) {
RenderHelper.draw(matrixStack, center.right - remWidth, y, ninePatch.center.u, ninePatch.center.v, remWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height) RenderHelper.draw(matrixStack, center.right - remWidth, y, ninePatch.center.u, ninePatch.center.v, remWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height)
} }

View File

@ -41,7 +41,9 @@ class EnumButton<E: Enum<E>>(
value = when (mouseButton) { value = when (mouseButton) {
MouseButton.LEFT -> EnumHelper.next(value) MouseButton.LEFT -> EnumHelper.next(value)
MouseButton.RIGHT -> EnumHelper.previous(value) MouseButton.RIGHT -> EnumHelper.previous(value)
else -> value else -> {
return false
}
} }
} }

View File

@ -1,6 +1,7 @@
package net.shadowfacts.cacao.view.textfield package net.shadowfacts.cacao.view.textfield
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.TickableElement
import net.minecraft.client.gui.widget.TextFieldWidget import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.util.math.MatrixStack import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.LiteralText import net.minecraft.text.LiteralText
@ -24,7 +25,7 @@ import org.lwjgl.glfw.GLFW
*/ */
abstract class AbstractTextField<Impl: AbstractTextField<Impl>>( abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
initialText: String initialText: String
): View() { ): View(), TickableElement {
/** /**
* A function that is invoked when the text in this text field changes. * A function that is invoked when the text in this text field changes.
@ -163,6 +164,10 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
return result || (isFirstResponder && keyCode != GLFW.GLFW_KEY_ESCAPE) return result || (isFirstResponder && keyCode != GLFW.GLFW_KEY_ESCAPE)
} }
override fun tick() {
minecraftWidget.tick()
}
// todo: label for the TextFieldWidget? // todo: label for the TextFieldWidget?
private class ProxyWidget: TextFieldWidget(MinecraftClient.getInstance().textRenderer, 0, 0, 0, 0, LiteralText("")) { private class ProxyWidget: TextFieldWidget(MinecraftClient.getInstance().textRenderer, 0, 0, 0, 0, LiteralText("")) {
// AbstractButtonWidget.height is protected // AbstractButtonWidget.height is protected

View File

@ -3,7 +3,7 @@ package net.shadowfacts.cacao.view.textfield
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class NumberField( open class NumberField(
initialValue: Int, initialValue: Int,
handler: ((NumberField) -> Unit)? = null, handler: ((NumberField) -> Unit)? = null,
): AbstractTextField<NumberField>(initialValue.toString()) { ): AbstractTextField<NumberField>(initialValue.toString()) {

View File

@ -7,7 +7,7 @@ package net.shadowfacts.cacao.view.textfield
* @param initialText The initial value of this text field. * @param initialText The initial value of this text field.
* @param handler A function that is invoked when the value of the text field changes. * @param handler A function that is invoked when the value of the text field changes.
*/ */
class TextField( open class TextField(
initialText: String, initialText: String,
handler: ((TextField) -> Unit)? = null handler: ((TextField) -> Unit)? = null
): AbstractTextField<TextField>(initialText) { ): AbstractTextField<TextField>(initialText) {

View File

@ -129,10 +129,9 @@ class RedstoneEmitterScreen(
inv.leftAnchor equalTo (minX + 8) inv.leftAnchor equalTo (minX + 8)
inv.topAnchor equalTo (minY + 72) inv.topAnchor equalTo (minY + 72)
// offset by 1 on each edge to account for MC border
field.widthAnchor equalTo 82 field.widthAnchor equalTo 82
field.heightAnchor equalTo 11 field.heightAnchor equalTo 11
field.leftAnchor equalTo (minX + 56) field.leftAnchor equalTo (minX + 57)
field.topAnchor equalTo (minY + 23) field.topAnchor equalTo (minY + 23)
hStack.centerXAnchor equalTo view.centerXAnchor hStack.centerXAnchor equalTo view.centerXAnchor

View File

@ -0,0 +1,75 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.geometry.Rect
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.View
import net.shadowfacts.phycon.PhysicalConnectivity
/**
* @author shadowfacts
*/
class ScrollTrackView(
val scrollPositionChanged: (ScrollTrackView) -> Unit,
): View() {
companion object {
private val THUMB = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png"), 52, 230)
private const val THUMB_WIDTH = 12.0
private const val THUMB_HEIGHT = 15.0
}
private lateinit var thumbView: TextureView
private var grabbedY: Double? = null
/**
* The [0,1] normalized position of the scroll thumb.
*/
var scrollPosition: Double
get() = thumbView.frame.top / (frame.height - THUMB_HEIGHT)
set(value) {
val newTop = MathHelper.clamp(value, 0.0, 1.0) * (frame.height - THUMB_HEIGHT)
thumbView.frame = Rect(0.0, newTop, THUMB_WIDTH, THUMB_HEIGHT)
}
init {
respondsToDragging = true
}
override fun wasAdded() {
super.wasAdded()
thumbView = addSubview(TextureView(THUMB).apply {
usesConstraintBasedLayout = false
frame = Rect(0.0, 0.0, THUMB_WIDTH, THUMB_HEIGHT)
})
}
override fun mouseDragged(point: Point, delta: Point, mouseButton: MouseButton): Boolean {
if (grabbedY == null && point !in thumbView.frame) {
val newCenter = MathHelper.clamp(point.y, THUMB_HEIGHT / 2, frame.height - THUMB_HEIGHT / 2)
thumbView.frame = Rect(0.0, newCenter - THUMB_HEIGHT / 2, THUMB_WIDTH, THUMB_HEIGHT)
}
if (grabbedY == null) {
grabbedY = point.y - thumbView.frame.top
}
val newTop = MathHelper.clamp(point.y - grabbedY!!, 0.0, frame.height - THUMB_HEIGHT)
thumbView.frame = Rect(0.0, newTop, THUMB_WIDTH, THUMB_HEIGHT)
scrollPositionChanged(this)
return true
}
override fun mouseDragEnded(point: Point, mouseButton: MouseButton) {
grabbedY = null
}
}

View File

@ -0,0 +1,57 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.util.Identifier
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.geometry.Size
import net.shadowfacts.cacao.util.EnumHelper
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.button.AbstractButton
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.util.SortMode
/**
* @author shadowfacts
*/
class SortModeButton(
initialValue: SortMode,
): AbstractButton<SortModeButton>(
TextureView(TEXTURES[initialValue]!!).apply {
intrinsicContentSize = Size(16.0, 16.0)
}
) {
companion object {
private val ID = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
private val TEXTURES = mapOf(
SortMode.COUNT_HIGH_FIRST to Texture(ID, 0, 230),
SortMode.COUNT_LOW_FIRST to Texture(ID, 16, 230),
SortMode.ALPHABETICAL to Texture(ID, 32, 230),
)
}
private val textureView: TextureView
get() = content as TextureView
var value: SortMode = initialValue
set(value) {
field = value
textureView.texture = TEXTURES[value]!!
}
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
if (!disabled) {
value = when (mouseButton) {
MouseButton.LEFT -> EnumHelper.next(value)
MouseButton.RIGHT -> EnumHelper.previous(value)
else -> {
return false
}
}
}
return super.mouseClicked(point, mouseButton)
}
}

View File

@ -0,0 +1,151 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
import net.shadowfacts.cacao.util.KeyModifiers
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.Label
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.button.Button
import net.shadowfacts.cacao.view.textfield.NumberField
import net.shadowfacts.cacao.viewcontroller.ViewController
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.PhysicalConnectivity
import org.lwjgl.glfw.GLFW
import kotlin.math.ceil
import kotlin.math.floor
/**
* @author shadowfacts
*/
class TerminalRequestAmountViewController(
val screen: TerminalScreen,
val stack: ItemStack,
): ViewController() {
companion object {
private val BACKGROUND = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal_amount.png"), 0, 0)
}
lateinit var field: NumberField
private set
override fun viewDidLoad() {
super.viewDidLoad()
val pane = view.addLayoutGuide()
view.solver.dsl {
pane.widthAnchor equalTo 158
pane.heightAnchor equalTo 62
pane.centerXAnchor equalTo view.centerXAnchor
pane.centerYAnchor equalTo view.centerYAnchor
}
val background = view.addSubview(TextureView(BACKGROUND)).apply {
zIndex = -1.0
}
field = view.addSubview(AmountField(this)).apply {
drawBackground = false
}
field.becomeFirstResponder()
val requestLabel = Label("Request", shadow = true)
val request = view.addSubview(Button(requestLabel) {
doRequest()
})
val plusOneLabel = Label("+1", shadow = true)
val plusOne = view.addSubview(Button(plusOneLabel) {
field.number = (field.number ?: 1) + 1
})
val plusTenLabel = Label("+10", shadow = true)
val plusTen = view.addSubview(Button(plusTenLabel) {
val old = field.number ?: 1
field.number = ceil((old + 1) / 10.0).toInt() * 10
})
val plusHundredLabel = Label("+100", shadow = true)
val plusHundred = view.addSubview(Button(plusHundredLabel) {
val old = field.number ?: 1
field.number = ceil((old + 1) / 100.0).toInt() * 100
})
val minusOneLabel = Label("-1", shadow = true)
val minusOne = view.addSubview(Button(minusOneLabel) {
field.number = (field.number ?: 1) - 1
})
val minusTenLabel = Label("-10", shadow = true)
val minusTen = view.addSubview(Button(minusTenLabel) {
val old = field.number ?: 1
field.number = floor((old - 1) / 10.0).toInt() * 10
})
val minusHundredLabel = Label("-100", shadow = true)
val minusHundred = view.addSubview(Button(minusHundredLabel) {
val old = field.number ?: 1
field.number = floor((old - 1) / 100.0).toInt() * 100
})
view.solver.dsl {
background.leftAnchor equalTo pane.leftAnchor
background.rightAnchor equalTo pane.rightAnchor
background.topAnchor equalTo pane.topAnchor
background.bottomAnchor equalTo pane.bottomAnchor
field.leftAnchor equalTo (pane.leftAnchor + 8)
field.topAnchor equalTo (pane.topAnchor + 27)
field.widthAnchor equalTo 80
field.heightAnchor equalTo 9
request.leftAnchor equalTo (pane.leftAnchor + 101)
request.centerYAnchor equalTo field.centerYAnchor
request.widthAnchor equalTo 50
request.heightAnchor equalTo 20
plusOne.leftAnchor equalTo (pane.leftAnchor + 7)
plusTen.leftAnchor equalTo (plusOne.rightAnchor + 3)
plusHundred.leftAnchor equalTo (plusTen.rightAnchor + 3)
plusHundred.rightAnchor equalTo (pane.leftAnchor + 97)
plusOne.widthAnchor equalTo plusTen.widthAnchor
plusOne.widthAnchor equalTo plusHundred.widthAnchor
plusOne.topAnchor equalTo (pane.topAnchor + 7)
plusTen.topAnchor equalTo (pane.topAnchor + 7)
plusHundred.topAnchor equalTo (pane.topAnchor + 7)
plusOne.heightAnchor equalTo 14
plusTen.heightAnchor equalTo 14
plusHundred.heightAnchor equalTo 14
minusOne.leftAnchor equalTo (pane.leftAnchor + 7)
minusTen.leftAnchor equalTo (minusOne.rightAnchor + 3)
minusHundred.leftAnchor equalTo (minusTen.rightAnchor + 3)
minusHundred.rightAnchor equalTo (pane.leftAnchor + 97)
minusOne.widthAnchor equalTo minusTen.widthAnchor
minusOne.widthAnchor equalTo minusHundred.widthAnchor
minusOne.topAnchor equalTo (pane.topAnchor + 41)
minusTen.topAnchor equalTo (pane.topAnchor + 41)
minusHundred.topAnchor equalTo (pane.topAnchor + 41)
minusOne.heightAnchor equalTo 14
minusTen.heightAnchor equalTo 14
minusHundred.heightAnchor equalTo 14
}
}
private fun doRequest() {
screen.requestItem(stack, field.number ?: 1)
window!!.removeFromScreen()
screen.amountVC = null
}
class AmountField(val vc: TerminalRequestAmountViewController): NumberField(1) {
override fun keyPressed(keyCode: Int, modifiers: KeyModifiers): Boolean {
return if (keyCode == GLFW.GLFW_KEY_ENTER) {
vc.doRequest()
true
} else {
super.keyPressed(keyCode, modifiers)
}
}
}
}

View File

@ -3,10 +3,7 @@ package net.shadowfacts.phycon.block.terminal
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawableHelper import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.Element
import net.minecraft.client.gui.widget.AbstractButtonWidget
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.gui.widget.TextFieldWidget import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.render.Tessellator import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.VertexConsumerProvider
@ -17,235 +14,64 @@ import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.LiteralText import net.minecraft.text.LiteralText
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.text.TranslatableText
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper import net.shadowfacts.cacao.CacaoHandledScreen
import net.shadowfacts.cacao.window.ScreenHandlerWindow
import net.shadowfacts.cacao.window.Window
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
import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.next
import net.shadowfacts.phycon.util.prev
import org.lwjgl.glfw.GLFW
import java.lang.NumberFormatException
import java.math.RoundingMode import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
// todo: translate title class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): CacaoHandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
companion object { companion object {
private val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") private val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
private val DIALOG = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal_amount.png")
} }
private lateinit var searchBox: TextFieldWidget val backgroundWidth: Int
private lateinit var sortButton: SortButton get() = backgroundWidth
var sortButtonX: Int = 0 val backgroundHeight: Int
private set get() = backgroundHeight
var sortButtonY = 0
private set
private lateinit var amountBox: TextFieldWidget
private var dialogStack = ItemStack.EMPTY
private var showingAmountDialog = false
set(value) {
val oldValue = field
field = value
for (e in dialogChildren) {
e.visible = value
}
amountBox.isVisible
searchBox.setSelected(!value)
amountBox.setSelected(value)
if (value && !oldValue) {
amountBox.text = "1"
}
updateFocusedElement()
}
private var dialogChildren = mutableListOf<AbstractButtonWidget>()
private var scrollPosition = 0f val terminalVC = TerminalViewController(this, handler, handler.terminal)
private var isDraggingScrollThumb = false var amountVC: TerminalRequestAmountViewController? = null
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 var searchQuery = ""
private val dialogHeight = 62 var scrollPosition = 0.0
var sortMode = SortMode.COUNT_HIGH_FIRST
init { init {
backgroundWidth = 252 backgroundWidth = 252
backgroundHeight = 222 backgroundHeight = 222
}
override fun init() { addWindow(ScreenHandlerWindow(handler, terminalVC))
super.init()
children.clear()
dialogChildren.clear()
client!!.keyboard.setRepeatEvents(true)
searchBox = TextFieldWidget(textRenderer, x + 138, y + 6, 80, 9, LiteralText("Search"))
searchBox.setMaxLength(50)
// setHasBorder is actually setDrawsBackground
searchBox.setHasBorder(false)
searchBox.isVisible = true
searchBox.setSelected(true)
searchBox.setEditableColor(0xffffff)
addChild(searchBox)
sortButtonX = x + 256
sortButtonY = y
sortButton = SortButton(sortButtonX, sortButtonY, handler.sortMode, {
requestUpdatedItems()
}, ::renderTooltip)
addButton(sortButton)
val dialogMinX = width / 2 - dialogWidth / 2
val dialogMinY = height / 2 - dialogHeight / 2
amountBox = TextFieldWidget(textRenderer, dialogMinX + 8, dialogMinY + 27, 80, 9, LiteralText("Amount"))
amountBox.setHasBorder(false)
amountBox.isVisible = false
amountBox.setSelected(false)
amountBox.setEditableColor(0xffffff)
amountBox.setTextPredicate {
if (it.isEmpty()) {
true
} else {
try {
Integer.parseInt(it) > 0
} catch (e: NumberFormatException) {
false
}
}
}
dialogChildren.add(amountBox)
val plusOne = SmallButton(dialogMinX + 7, dialogMinY + 7, 28, LiteralText("+1")) {
amountBox.intValue += 1
}
dialogChildren.add(plusOne)
val plusTen = SmallButton(dialogMinX + 7 + 28 + 3, dialogMinY + 7, 28, LiteralText("+10")) {
amountBox.intValue = ceil((amountBox.intValue + 1) / 10.0).toInt() * 10
}
dialogChildren.add(plusTen)
val plusHundred = SmallButton(dialogMinX + 7 + (28 + 3) * 2, dialogMinY + 7, 28, LiteralText("+100")) {
amountBox.intValue = ceil((amountBox.intValue + 1) / 100.0).toInt() * 100
}
dialogChildren.add(plusHundred)
val minusOne = SmallButton(dialogMinX + 7, dialogMinY + 39, 28, LiteralText("-1")) {
amountBox.intValue -= 1
}
dialogChildren.add(minusOne)
val minusTen = SmallButton(dialogMinX + 7 + 28 + 3, dialogMinY + 39, 28, LiteralText("-10")) {
amountBox.intValue = floor((amountBox.intValue - 1) / 10.0).toInt() * 10
}
dialogChildren.add(minusTen)
val minusHundred = SmallButton(dialogMinX + 7 + (28 + 3) * 2, dialogMinY + 39, 28, LiteralText("-100")) {
amountBox.intValue = floor((amountBox.intValue - 1) / 100.0).toInt() * 100
}
dialogChildren.add(minusHundred)
// 101,25
val request = ButtonWidget(dialogMinX + 101, dialogMinY + 21, 50, 20, LiteralText("Request")) {
doDialogRequest()
}
dialogChildren.add(request)
updateFocusedElement()
requestUpdatedItems() requestUpdatedItems()
} }
private fun updateFocusedElement() { fun requestItem(stack: ItemStack, amount: Int) {
focused = if (showingAmountDialog) { val netHandler = MinecraftClient.getInstance().player!!.networkHandler
amountBox val packet = C2STerminalRequestItem(handler.terminal, stack, amount)
} else if (searchBox.isFocused) { netHandler.sendPacket(packet)
searchBox
} else {
null
}
} }
private fun requestUpdatedItems() { fun requestUpdatedItems() {
val player = MinecraftClient.getInstance().player!! val player = MinecraftClient.getInstance().player!!
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchBox.text, sortButton.mode, scrollPosition)) player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchQuery, sortMode, scrollPosition.toFloat()))
} }
override fun tick() { private fun showRequestAmountDialog(stack: ItemStack) {
super.tick() val vc = TerminalRequestAmountViewController(this, stack)
searchBox.tick() addWindow(Window(vc))
amountBox.tick() amountVC = vc
}
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040)
textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040)
textRenderer.draw(matrixStack, TranslatableText("gui.phycon.terminal_buffer"), 7f, 6f, 0x404040)
}
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
// if the dialog is open, the background gradient will be drawn in front of the main terminal gui
if (!showingAmountDialog) {
renderBackground(matrixStack)
}
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND)
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
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
if (showingAmountDialog) {
RenderSystem.pushMatrix()
// items are rendered at some stupidly high z offset. item amounts at an even higher one
RenderSystem.translatef(0f, 0f, -350f)
// fake the mouse x/y while showing a dialog so slot mouseover highlights aren't drawn
super.render(matrixStack, -1, -1, delta)
RenderSystem.popMatrix()
} else {
super.render(matrixStack, mouseX, mouseY, delta)
}
searchBox.render(matrixStack, mouseX, mouseY, delta)
if (showingAmountDialog) {
renderBackground(matrixStack)
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(DIALOG)
val dialogMinX = width / 2 - dialogWidth / 2
val dialogMinY = height / 2 - dialogHeight / 2
drawTexture(matrixStack, dialogMinX, dialogMinY, 0, 0, dialogWidth, dialogHeight)
for (e in dialogChildren) {
e.render(matrixStack, mouseX, mouseY, delta)
}
} else {
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
}
} }
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
@ -299,21 +125,29 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
matrixStack.pop() matrixStack.pop()
} }
private fun isPointInsScrollThumb(mouseX: Double, mouseY: Double): Boolean { override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
super.drawBackground(matrixStack, delta, mouseX, mouseY)
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND)
val x = (width - backgroundWidth) / 2 val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2 val y = (height - backgroundHeight) / 2
val thumbMinX = x + 232 drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
val thumbMaxX = thumbMinX + thumbWidth }
val thumbMinY = y + scrollThumbTop
val thumbMaxY = thumbMinY + thumbHeight override fun tick() {
return mouseX >= thumbMinX && mouseX < thumbMaxX && mouseY >= thumbMinY && mouseY < thumbMaxY super.tick()
if (amountVC != null) {
amountVC!!.field.tick()
} else {
terminalVC.searchField.tick()
}
} }
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)
updateFocusedElement()
if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id)) { if (slot != null && !slot.stack.isEmpty && handler.isNetworkSlot(slot.id)) {
val stack = slot.stack val stack = slot.stack
@ -325,210 +159,18 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
// right click, request half stack // right click, request half stack
requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt()) requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt())
} else { } else {
dialogStack = stack showRequestAmountDialog(stack)
showingAmountDialog = true
searchBox.setSelected(false)
} }
} }
} }
} }
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { private val fakeFocusedElement = TextFieldWidget(textRenderer, 0, 0, 0, 0, LiteralText(""))
if (showingAmountDialog) { override fun getFocused(): Element? {
for (e in dialogChildren) { return if (windows.last().firstResponder != null) {
if (e.mouseClicked(mouseX, mouseY, button)) { fakeFocusedElement
return true
}
}
return false
} else { } else {
if (isPointInsScrollThumb(mouseX, mouseY)) { null
isDraggingScrollThumb = true
return true
}
return super.mouseClicked(mouseX, mouseY, button)
}
}
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(mouseX, mouseY, button, deltaX, deltaY)
}
}
override fun mouseMoved(d: Double, e: Double) {
if (showingAmountDialog) {
} else {
super.mouseMoved(d, e)
}
}
override fun mouseReleased(d: Double, e: Double, i: Int): Boolean {
if (showingAmountDialog) {
return false
} else {
isDraggingScrollThumb = false
return super.mouseReleased(d, e, i)
}
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
if (showingAmountDialog) {
return false
} else {
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)
}
}
override fun charTyped(c: Char, i: Int): Boolean {
if (showingAmountDialog) {
return amountBox.charTyped(c, i)
} else {
val oldText = searchBox.text
if (searchBox.charTyped(c, i)) {
if (searchBox.text != oldText) {
scrollPosition = 0f
requestUpdatedItems()
}
return true
}
return super.charTyped(c, i)
}
}
override fun keyPressed(key: Int, j: Int, k: Int): Boolean {
if (showingAmountDialog) {
return when (key) {
GLFW.GLFW_KEY_ESCAPE -> {
showingAmountDialog = false
true
}
GLFW.GLFW_KEY_ENTER -> {
doDialogRequest()
true
}
else -> {
amountBox.keyPressed(key, j, k)
}
}
} else {
val oldText = searchBox.text
if (searchBox.keyPressed(key, j, k)) {
if (searchBox.text != oldText) {
scrollPosition = 0f
requestUpdatedItems()
}
return true
}
return if (searchBox.isFocused && searchBox.isVisible && key != GLFW.GLFW_KEY_ESCAPE) {
true
} else {
super.keyPressed(key, j, k)
}
}
}
private fun doDialogRequest() {
showingAmountDialog = false
requestItem(dialogStack, amountBox.intValue)
}
private fun requestItem(stack: ItemStack, amount: Int) {
val netHandler = MinecraftClient.getInstance().player!!.networkHandler
val packet = C2STerminalRequestItem(handler.terminal, stack, amount)
netHandler.sendPacket(packet)
}
private var TextFieldWidget.intValue: Int
get() = if (text.isEmpty()) 0 else Integer.parseInt(text)
set(value) {
text = value.toString()
setSelected(true)
}
class SmallButton(x: Int, y: Int, width: Int, title: Text, action: PressAction): ButtonWidget(x, y, width, 14, title, action) {
@ExperimentalUnsignedTypes
override fun renderButton(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
val client = MinecraftClient.getInstance()
client.textureManager.bindTexture(DIALOG)
RenderSystem.color4f(1f, 1f, 1f, 1f)
val v = if (isHovered) 142 else 128
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
RenderSystem.enableDepthTest()
drawTexture(matrixStack, x, y, 0, v, width / 2, height)
drawTexture(matrixStack, x + width / 2, y, 200 - width / 2, v, width / 2, height)
drawCenteredText(matrixStack, client.textRenderer, message, x + width / 2, y + (height - 8) / 2, 0xffffffffu.toInt())
}
}
class SortButton(
x: Int,
y: Int,
var mode: SortMode,
val onChange: (SortMode) -> Unit,
val doRenderTooltip: (MatrixStack, Text, Int, Int) -> Unit
): AbstractPressableButtonWidget(x, y, 20, 20, LiteralText("")) {
override fun onPress() {}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if ((button == 0 || button == 1) && clicked(mouseX, mouseY)) {
val newVal = if (button == 0) mode.next else mode.prev
mode = newVal
onChange(mode)
playDownSound(MinecraftClient.getInstance().soundManager)
return true
}
return false
}
override fun renderButton(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
val client = MinecraftClient.getInstance()
RenderSystem.color4f(1f, 1f, 1f, 1f)
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
RenderSystem.enableDepthTest()
client.textureManager.bindTexture(WIDGETS_LOCATION)
val k = getYImage(isHovered)
drawTexture(matrixStack, x, y, 0, 46 + k * 20, width / 2, height)
drawTexture(matrixStack, x + width / 2, y, 200 - width / 2, 46 + k * 20, width / 2, height)
client.textureManager.bindTexture(BACKGROUND)
val u: Int = when (mode) {
SortMode.COUNT_HIGH_FIRST -> 0
SortMode.COUNT_LOW_FIRST -> 16
SortMode.ALPHABETICAL -> 32
}
drawTexture(matrixStack, x + 2, y + 2, u, 230, 16, 16)
if (isHovered) {
renderToolTip(matrixStack, mouseX, mouseY)
}
}
override fun renderToolTip(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
val text = LiteralText("")
text.append("Sort by: ")
text.append(mode.tooltip)
doRenderTooltip(matrixStack, text, mouseX, mouseY)
} }
} }

View File

@ -40,7 +40,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
private set private set
var totalEntries = 0 var totalEntries = 0
private set private set
private var scrollPosition = 0f var scrollPosition = 0f
private var itemEntries = listOf<Entry>() private var itemEntries = listOf<Entry>()
set(value) { set(value) {
field = value field = value

View File

@ -0,0 +1,159 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.text.TranslatableText
import net.minecraft.util.math.MathHelper
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.view.Label
import net.shadowfacts.cacao.view.View
import net.shadowfacts.cacao.view.textfield.TextField
import net.shadowfacts.cacao.viewcontroller.ViewController
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.util.SortMode
/**
* @author shadowfacts
*/
class TerminalViewController(
val screen: TerminalScreen,
val handler: TerminalScreenHandler,
val terminal: TerminalBlockEntity,
): ViewController() {
private lateinit var scrollTrack: ScrollTrackView
lateinit var sortMode: SortModeButton
private set
lateinit var searchField: TextField
private set
override fun loadView() {
view = ScrollHandlingView(this)
}
override fun viewDidLoad() {
super.viewDidLoad()
val pane = view.addLayoutGuide()
view.solver.dsl {
pane.centerXAnchor equalTo view.centerXAnchor
pane.centerYAnchor equalTo view.centerYAnchor
pane.widthAnchor equalTo screen.backgroundWidth
pane.heightAnchor equalTo screen.backgroundHeight
}
val buffer = view.addLayoutGuide()
view.solver.dsl {
buffer.leftAnchor equalTo (pane.leftAnchor + 7)
buffer.topAnchor equalTo (pane.topAnchor + 17)
buffer.widthAnchor equalTo (18 * 3)
buffer.heightAnchor equalTo (18 * 6)
}
val network = view.addLayoutGuide()
view.solver.dsl {
network.leftAnchor equalTo (pane.leftAnchor + 65)
network.topAnchor equalTo buffer.topAnchor
network.widthAnchor equalTo (18 * 9)
network.heightAnchor equalTo (18 * 6)
}
val playerInv = view.addLayoutGuide()
view.solver.dsl {
playerInv.leftAnchor equalTo network.leftAnchor
playerInv.topAnchor equalTo (pane.topAnchor + 139)
playerInv.widthAnchor equalTo (18 * 9)
playerInv.heightAnchor equalTo 76
}
val titleLabel = view.addSubview(Label(screen.title)).apply {
textColor = Color.TEXT
}
val playerInvLabel = view.addSubview(Label(handler.playerInv.displayName)).apply {
textColor = Color.TEXT
}
val bufferLabel = view.addSubview(Label(TranslatableText("gui.phycon.terminal_buffer"))).apply {
textColor = Color.TEXT
}
searchField = view.addSubview(TerminalSearchField()).apply {
handler = ::searchFieldChanged
drawBackground = false
}
searchField.becomeFirstResponder()
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
sortMode = view.addSubview(SortModeButton(SortMode.COUNT_HIGH_FIRST)).apply {
handler = ::sortModeChanged
}
view.solver.dsl {
titleLabel.leftAnchor equalTo network.leftAnchor
titleLabel.topAnchor equalTo (pane.topAnchor + 6)
bufferLabel.leftAnchor equalTo buffer.leftAnchor
bufferLabel.topAnchor equalTo titleLabel.topAnchor
playerInvLabel.leftAnchor equalTo playerInv.leftAnchor
playerInvLabel.topAnchor equalTo (pane.bottomAnchor - 94)
searchField.leftAnchor equalTo (pane.leftAnchor + 138)
searchField.topAnchor equalTo (pane.topAnchor + 5)
searchField.widthAnchor equalTo 80
searchField.heightAnchor equalTo 9
scrollTrack.leftAnchor equalTo (pane.leftAnchor + 232)
scrollTrack.topAnchor equalTo (network.topAnchor + 1)
scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1)
scrollTrack.widthAnchor equalTo 12
sortMode.leftAnchor equalTo pane.rightAnchor + 4
sortMode.topAnchor equalTo pane.topAnchor
sortMode.widthAnchor equalTo 20
sortMode.heightAnchor equalTo 20
}
}
private fun searchFieldChanged(field: TextField) {
screen.searchQuery = field.text
screen.requestUpdatedItems()
}
private fun scrollPositionChanged(track: ScrollTrackView) {
val oldOffset = handler.currentScrollOffsetInRows()
handler.scrollPosition = track.scrollPosition.toFloat()
screen.scrollPosition = track.scrollPosition
if (handler.currentScrollOffsetInRows() != oldOffset) {
screen.requestUpdatedItems()
}
}
private fun sortModeChanged(button: SortModeButton) {
screen.sortMode = button.value
screen.requestUpdatedItems()
}
class TerminalSearchField: TextField("") {
override fun resignFirstResponder() {
// no-op
}
}
class ScrollHandlingView(val vc: TerminalViewController): View() {
override fun mouseScrolled(point: Point, amount: Double): Boolean {
var newOffsetInRows = vc.handler.currentScrollOffsetInRows() - amount.toInt()
newOffsetInRows = MathHelper.clamp(newOffsetInRows, 0, vc.handler.maxScrollOffsetInRows())
if (newOffsetInRows != vc.handler.currentScrollOffsetInRows()) {
val newScrollPosition = newOffsetInRows / vc.handler.maxScrollOffsetInRows().toDouble()
vc.screen.scrollPosition = newScrollPosition
vc.scrollTrack.scrollPosition = newScrollPosition
vc.screen.requestUpdatedItems()
}
return true
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 2.2 KiB