ocelot-desktop/src/main/scala/ocelot/desktop/windows/OcelotInterfaceWindow.scala
2025-09-03 11:39:43 +02:00

149 lines
4.7 KiB
Scala

package ocelot.desktop.windows
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.ui.event.KeyEvent
import ocelot.desktop.ui.layout.{AlignItems, Layout, LinearLayout}
import ocelot.desktop.ui.widget.LogWidget.{LogEntry, TextLogEntry}
import ocelot.desktop.ui.widget.window.PanelWindow
import ocelot.desktop.ui.widget.{Button, Checkbox, Filler, Label, LogWidget, PaddingBox, TextInput, Widget}
import ocelot.desktop.util.{OcelotInterfaceLogStorage, Orientation}
import ocelot.desktop.windows.OcelotInterfaceWindow.ScrollToEndTag
import org.lwjgl.input.Keyboard
import totoro.ocelot.brain.nbt.NBTTagCompound
class OcelotInterfaceWindow(storage: OcelotInterfaceLogStorage) extends PanelWindow {
override protected def title: String = s"${storage.name} ${storage.ocelotInterface.node.address}"
private val logWidget: LogWidget = new LogWidget {
override protected def textWidth: Int = 50
override def minimumSize: Size2D = super.minimumSize.copy(height = 300)
override def maximumSize: Size2D = minimumSize
}
setInner(new Widget {
override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical, gap = 4f)
children :+= logWidget
var historyPosition = 0
var unfinishedEntryBackup: Option[String] = None
children :+= new TextInput() {
eventHandlers += {
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_UP | Keyboard.KEY_DOWN, _) if isFocused =>
val currentInput = text
val index = if (event.code == Keyboard.KEY_UP) {
storage.findLastTextEntry(currentInput, storage.entryCount - historyPosition)
} else {
storage.findFirstTextEntry(currentInput, storage.entryCount - historyPosition + 1)
}
if (index != -1) {
if (unfinishedEntryBackup.isEmpty) {
unfinishedEntryBackup = Some(currentInput)
}
historyPosition = storage.entryCount - index
text = storage.getEntry(index).asInstanceOf[TextLogEntry].message
event.consume()
} else if (event.code == Keyboard.KEY_DOWN && unfinishedEntryBackup.nonEmpty) {
text = unfinishedEntryBackup.get
unfinishedEntryBackup = None
}
}
override def onConfirm(): Unit = {
pushLine(text)
text = ""
unfinishedEntryBackup = None
historyPosition = 0
}
}
children :+= new Label {
override def text: String = s"Messages: ${storage.entryCount} / ${storage.messageLimit}"
}
children :+= new Widget {
override protected val layout: Layout =
new LinearLayout(this, orientation = Orientation.Horizontal, alignItems = AlignItems.Center)
children :+= new PaddingBox(
new Label {
override def text: String = "Limit"
override def maximumSize: Size2D = minimumSize
},
Padding2D(right = 12),
)
children :+= new TextInput(storage.messageLimit.toString) {
private def parseInput(text: String): Option[Int] = text.toIntOption.filter(_ > 0)
override def minimumSize: Size2D = super.minimumSize.copy(width = 60)
override def maximumSize: Size2D = minimumSize
override def validator(text: String): Boolean = parseInput(text).nonEmpty
override def onConfirm(): Unit = {
for (messageLimit <- parseInput(text)) {
storage.messageLimit = messageLimit
}
super.onConfirm()
}
}
children :+= new Filler
children :+= new Checkbox("Scroll to end") {
override def checked: Boolean = logWidget.scrollToEnd
override def checked_=(value: Boolean): Unit = {
logWidget.scrollToEnd = value
}
}
children :+= new Button {
override def text: String = "Clear"
override def onClick(): Unit = {
unfinishedEntryBackup = None
historyPosition = 0
clear()
}
}
}
})
private def clear(): Unit = {
storage.clear()
}
def onMessagesAdded(entries: Iterable[LogEntry]): Unit = {
logWidget.addEntries(entries)
}
def onMessagesRemoved(count: Int): Unit = {
logWidget.removeFirstEntries(count)
}
def pushLine(line: String): Unit = {
storage.ocelotInterface.pushMessage(line)
}
override def save(nbt: NBTTagCompound): Unit = {
super.save(nbt)
nbt.setBoolean(ScrollToEndTag, logWidget.scrollToEnd)
}
override def load(nbt: NBTTagCompound): Unit = {
super.load(nbt)
if (nbt.hasKey(ScrollToEndTag)) {
logWidget.scrollToEnd = nbt.getBoolean(ScrollToEndTag)
}
}
}
object OcelotInterfaceWindow {
private val ScrollToEndTag = "scrollToEnd"
}