Add navigation through Ocelot component log history

This commit is contained in:
UnicornFreedom 2025-08-22 14:27:56 +02:00
parent cf088ce9f7
commit 9a3ee8e95c
No known key found for this signature in database
GPG Key ID: B4ED0DB6B940024F
4 changed files with 52 additions and 6 deletions

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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()
}
}
}
})