diff --git a/src/main/scala/ocelot/desktop/ui/widget/LogWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/LogWidget.scala index 8b8f033..b2972de 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/LogWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/LogWidget.scala @@ -222,12 +222,16 @@ object LogWidget { sealed trait LogEntry + sealed trait TextLogEntry extends LogEntry { + val message: String + } + object LogEntry { /** A message received from a log source. */ - case class Rx(message: String) extends LogEntry + case class Rx(message: String) extends TextLogEntry /** A message sent to a log source. */ - case class Tx(message: String) extends LogEntry + case class Tx(message: String) extends TextLogEntry } } diff --git a/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala b/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala index 4f35a7b..4516b58 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/TextInput.scala @@ -34,7 +34,7 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w private val prevCursorPosition = Register.sampling(cursor.position) // view - private var isFocused = false + protected var isFocused = false private var scroll = 0f private var blinkTimer = 0f private var cursorOffset = 0f diff --git a/src/main/scala/ocelot/desktop/util/OcelotInterfaceLogStorage.scala b/src/main/scala/ocelot/desktop/util/OcelotInterfaceLogStorage.scala index 820e81b..c498120 100644 --- a/src/main/scala/ocelot/desktop/util/OcelotInterfaceLogStorage.scala +++ b/src/main/scala/ocelot/desktop/util/OcelotInterfaceLogStorage.scala @@ -2,7 +2,7 @@ package ocelot.desktop.util import ocelot.desktop.entity.traits.OcelotInterface import ocelot.desktop.ui.event.{BrainEvent, EventAware} -import ocelot.desktop.ui.widget.LogWidget.LogEntry +import ocelot.desktop.ui.widget.LogWidget.{LogEntry, TextLogEntry} import ocelot.desktop.ui.widget.window.Windowed import ocelot.desktop.util.OcelotInterfaceLogStorage._ import ocelot.desktop.windows.OcelotInterfaceWindow @@ -121,6 +121,16 @@ trait OcelotInterfaceLogStorage extends EventAware with Persistable with Windowe window.onMessagesRemoved(count) } + def getEntry(index: Int): LogEntry = _entries(index) + + def findFirstTextEntry(exclude: String, start: Int): Int = { + _entries.indexWhere(it => it.isInstanceOf[TextLogEntry] && it.asInstanceOf[TextLogEntry].message != exclude, start) + } + + def findLastTextEntry(exclude: String, end: Int): Int = { + _entries.lastIndexWhere(it => it.isInstanceOf[TextLogEntry] && it.asInstanceOf[TextLogEntry].message != exclude, end) + } + private def addEntry(entry: LogEntry): Unit = { ensureFreeSpace(1) _entries += entry diff --git a/src/main/scala/ocelot/desktop/windows/OcelotInterfaceWindow.scala b/src/main/scala/ocelot/desktop/windows/OcelotInterfaceWindow.scala index 985481d..6769997 100644 --- a/src/main/scala/ocelot/desktop/windows/OcelotInterfaceWindow.scala +++ b/src/main/scala/ocelot/desktop/windows/OcelotInterfaceWindow.scala @@ -1,11 +1,13 @@ 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 +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 org.lwjgl.input.Keyboard class OcelotInterfaceWindow(storage: OcelotInterfaceLogStorage) extends PanelWindow { override protected def title: String = s"${storage.name} ${storage.ocelotInterface.node.address}" @@ -21,10 +23,36 @@ class OcelotInterfaceWindow(storage: OcelotInterfaceLogStorage) extends PanelWin 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 this.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 } } @@ -75,7 +103,11 @@ class OcelotInterfaceWindow(storage: OcelotInterfaceLogStorage) extends PanelWin children :+= new Button { override def text: String = "Clear" - override def onClick(): Unit = clear() + override def onClick(): Unit = { + unfinishedEntryBackup = None + historyPosition = 0 + clear() + } } } })