package net.shadowfacts.phycon.block.terminal import net.minecraft.text.TranslatableText import net.minecraft.util.math.MathHelper import net.shadowfacts.cacao.geometry.Axis import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.util.Color import net.shadowfacts.cacao.util.LayoutGuide import net.shadowfacts.cacao.util.MouseButton import net.shadowfacts.cacao.view.Label import net.shadowfacts.cacao.view.StackView 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.client.screen.ScrollTrackView import net.shadowfacts.phycon.util.TerminalSettings /** * @author shadowfacts */ abstract class AbstractTerminalViewController, H: AbstractTerminalScreenHandler>( val screen: S, val handler: H, val terminal: BE = handler.terminal, ): ViewController() { private lateinit var scrollTrack: ScrollTrackView lateinit var settingsView: View private set lateinit var searchField: TextField private set lateinit var pane: LayoutGuide private set lateinit var buffer: LayoutGuide private set lateinit var network: LayoutGuide private set lateinit var playerInv: LayoutGuide private set lateinit var networkLabel: View private set lateinit var playerInvLabel: View private set lateinit var bufferLabel: View private set override fun loadView() { view = ScrollHandlingView(this) } override fun viewDidLoad() { super.viewDidLoad() pane = view.addLayoutGuide() view.solver.dsl { pane.centerXAnchor equalTo view.centerXAnchor pane.centerYAnchor equalTo view.centerYAnchor pane.widthAnchor equalTo screen.terminalBackgroundWidth pane.heightAnchor equalTo screen.terminalBackgroundHeight } buffer = view.addLayoutGuide() view.solver.dsl { buffer.leftAnchor equalTo (pane.leftAnchor + 7 + handler.xOffset) buffer.topAnchor equalTo (pane.topAnchor + 17) buffer.widthAnchor equalTo (18 * 3) buffer.heightAnchor equalTo (18 * 6) } network = view.addLayoutGuide() view.solver.dsl { network.leftAnchor equalTo (pane.leftAnchor + 65 + handler.xOffset) network.topAnchor equalTo buffer.topAnchor network.widthAnchor equalTo (18 * 9) network.heightAnchor equalTo (18 * 6) } 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 } networkLabel = view.addSubview(Label(TranslatableText("gui.phycon.terminal_network"))).apply { textColor = Color.TEXT } playerInvLabel = view.addSubview(Label(handler.playerInv.displayName)).apply { textColor = Color.TEXT } bufferLabel = view.addSubview(Label(TranslatableText("gui.phycon.terminal_buffer"))).apply { textColor = Color.TEXT } searchField = view.addSubview(TerminalSearchField()).apply { handler = ::searchFieldChanged drawBackground = false } scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged)) val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0)) settingsView = settingsStack TerminalSettings.allKeys.sortedByDescending { it.priority }.forEach { key -> val button = SettingButton(key) button.handler = { settingsChanged() } settingsStack.addArrangedSubview(button) } view.solver.dsl { networkLabel.leftAnchor equalTo network.leftAnchor networkLabel.topAnchor equalTo (pane.topAnchor + 6) bufferLabel.leftAnchor equalTo buffer.leftAnchor bufferLabel.topAnchor equalTo networkLabel.topAnchor playerInvLabel.leftAnchor equalTo playerInv.leftAnchor playerInvLabel.topAnchor equalTo (pane.topAnchor + 128) searchField.leftAnchor equalTo (pane.leftAnchor + 138 + handler.xOffset) searchField.topAnchor equalTo (pane.topAnchor + 5) searchField.widthAnchor equalTo 80 searchField.heightAnchor equalTo 9 scrollTrack.leftAnchor equalTo (pane.leftAnchor + 232 + handler.xOffset) scrollTrack.topAnchor equalTo (network.topAnchor + 1) scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1) scrollTrack.widthAnchor equalTo 12 settingsStack.leftAnchor equalTo (pane.rightAnchor + 4) settingsStack.topAnchor equalTo pane.topAnchor } } override fun viewWillAppear() { super.viewWillAppear() searchField.becomeFirstResponder() } 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 settingsChanged() { screen.requestUpdatedItems() } class TerminalSearchField: TextField("") { override fun mouseClickedOutside(point: Point, mouseButton: MouseButton) { // no-op } } class ScrollHandlingView(val vc: AbstractTerminalViewController<*, *, *>): 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 } } }