Skip to content

Commit

Permalink
Merge pull request #171 from rladstaetter/170-current-element-selecti…
Browse files Browse the repository at this point in the history
…on-disappears

#170: fixes current element selection
  • Loading branch information
rladstaetter authored Nov 20, 2023
2 parents 424030f + f974be5 commit 08c5c8e
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 89 deletions.
6 changes: 3 additions & 3 deletions app/src/main/scala/app/logorrr/util/JfxUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import javafx.stage.{Stage, WindowEvent}
object JfxUtils extends CanLog {

def execOnUiThread(f: => Unit): Unit = {
if (!Platform.isFxApplicationThread) {
Platform.runLater(() => f)
} else {
if (Platform.isFxApplicationThread) {
f
} else {
Platform.runLater(() => f)
}
}

Expand Down
6 changes: 5 additions & 1 deletion app/src/main/scala/app/logorrr/views/block/BlockImage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ object BlockImage {
/** defines how many table cells should be rendered per list height */
val DefaultBlocksPerPage = 4

def indexOf(x: Int, y: Int, blockWidth: Int, blockViewWidth: Int): Int = y / blockWidth * (blockViewWidth / blockWidth) + x / blockWidth
// assuming we have a grid of rectangles, and x and y give the coordinate of a mouse click
// this function should return the correct index for the surrounding rectangle
def indexOf(x: Int, y: Int, blockWidth: Int, blockViewWidth: Int): Int = {
y / blockWidth * (blockViewWidth / blockWidth) + x / blockWidth
}

/**
* Calculates overall height of virtual canvas
Expand Down
19 changes: 13 additions & 6 deletions app/src/main/scala/app/logorrr/views/block/ChunkListCell.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import javafx.collections.ObservableList
import javafx.event.EventHandler
import javafx.scene.control.ListCell
import javafx.scene.image.ImageView
import javafx.scene.input.MouseEvent
import javafx.scene.input.{MouseButton, MouseEvent}

import scala.util.Try

Expand All @@ -25,17 +25,24 @@ class ChunkListCell(selectedLineNumberProperty: SimpleIntegerProperty
, widthProperty: ReadOnlyDoubleProperty
, blockSizeProperty: SimpleIntegerProperty
, filtersProperty: ObservableList[Filter]
, selectInTextView: LogEntry => Unit
) extends ListCell[Chunk] with CanLog {

// if user selects an entry in the ChunkListView set selectedLineNumberProperty. This property is observed
// via an listener and a yellow square will be painted.
val mouseEventHandler = new EventHandler[MouseEvent]() {
override def handle(me: MouseEvent): Unit = {
val index = BlockImage.indexOf(me.getX.toInt, me.getY.toInt, blockSizeProperty.get, widthProperty.get.toInt)
getEntryAt(getItem, index) match {
case Some(value) =>
selectedLineNumberProperty.set(value.lineNumber)
case None => System.err.println("no element found")
// on left mouse button
if (me.getButton.equals(MouseButton.PRIMARY)) {
val index = BlockImage.indexOf(me.getX.toInt, me.getY.toInt, blockSizeProperty.get, widthProperty.get.toInt)
getEntryAt(getItem, index) match {
case Some(value) =>
// set selected property such that the next repaint will highlight this entry
selectedLineNumberProperty.set(value.lineNumber)
// we have to select also the entry in the LogTextView, couldn't get it to work with bindings / listeners
selectInTextView(value)
case None => System.err.println("no element found")
}
}
}
}
Expand Down
16 changes: 10 additions & 6 deletions app/src/main/scala/app/logorrr/views/block/ChunkListView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ import scala.util.{Failure, Success, Try}
object ChunkListView {

def apply(entries: ObservableList[LogEntry]
, settings: MutLogFileSettings): ChunkListView = {
, settings: MutLogFileSettings
, selectInTextView: LogEntry => Unit
): ChunkListView = {
new ChunkListView(entries
, settings.selectedLineNumberProperty
, settings.blockSizeProperty
, settings.filtersProperty
, settings.dividerPositionProperty)
, settings.dividerPositionProperty
, selectInTextView)
}
}

Expand All @@ -40,7 +43,8 @@ class ChunkListView(val entries: ObservableList[LogEntry]
, val selectedLineNumberProperty: SimpleIntegerProperty
, val blockSizeProperty: SimpleIntegerProperty
, val filtersProperty: ObservableList[Filter]
, val dividersProperty: SimpleDoubleProperty)
, val dividersProperty: SimpleDoubleProperty
, selectInTextView: LogEntry => Unit)
extends ListView[Chunk] with CanLog {

var repaints = 0
Expand Down Expand Up @@ -73,11 +77,11 @@ class ChunkListView(val entries: ObservableList[LogEntry]

getStylesheets.add(getClass.getResource("/app/logorrr/ChunkListView.css").toExternalForm)

setCellFactory((lv: ListView[Chunk]) => new ChunkListCell(
selectedLineNumberProperty
setCellFactory((lv: ListView[Chunk]) => new ChunkListCell(selectedLineNumberProperty
, lv.widthProperty()
, blockSizeProperty
, filtersProperty))
, filtersProperty
, selectInTextView))


// if width/height of display is changed, also elements of this listview will change
Expand Down
65 changes: 21 additions & 44 deletions app/src/main/scala/app/logorrr/views/block/LPixelBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,18 @@ case class LPixelBuffer(blockNumber: Int
, IntBuffer.wrap(rawInts)
, PixelFormat.getIntArgbPreInstance) with CanLog {

val name = s"${range.start}_${range.end}"

getBuffer.clear()

assert(shape.width != 0, s"For $name, width was ${shape.width}.")
assert(shape.height != 0, s"For $name, height was ${shape.height}.")
assert(shape.height * shape.width > 0)

private val name = s"${range.start}_${range.end}"
private val bgColor: Int = ColorUtil.toARGB(Color.WHITE)
lazy val background: Array[Int] = Array.fill(shape.area)(bgColor)

paint()
init()

def init(): Unit = {
assert(shape.width != 0, s"For $name, width was ${shape.width}.")
assert(shape.height != 0, s"For $name, height was ${shape.height}.")
assert(shape.height * shape.width > 0)
paint()
}

private def cleanBackground(): Unit = System.arraycopy(background, 0, rawInts, 0, background.length)

Expand All @@ -96,46 +96,23 @@ case class LPixelBuffer(blockNumber: Int
def filters = Option(filtersProperty).map(_.asScala.toSeq).getOrElse(Seq())

// todo check visibility
def paint(): Unit = {
if (blockSize != 0) {
if (Option(filtersProperty).isEmpty) {
logWarn("filters is null")
} else {
JfxUtils.execOnUiThread(
updateBuffer((_: PixelBuffer[IntBuffer]) => {
cleanBackground()
var i = 0
entries.forEach(e => {
if (e.lineNumber.equals(selectedLineNumberProperty.getValue() + 1)) {
LPixelBuffer.drawRect(rawInts, i, shape.width, blockSize, Color.YELLOW)
} else {
// LPixelBuffer.drawRect(rawInts, i, width, blockSize, blockColor)
LPixelBuffer.drawRect(rawInts, i, shape.width, blockSize, Filter.calcColor(e.value, filters))
//LPixelBuffer.drawRect(rawInts, i, shape.width.toInt, blockSize, ColorUtil.randColor)
}
i = i + 1
})
shape
}))
}
} else {
logWarn(s"getBlockWidth() = $blockSize")
}
}


/**
* draws a filled rectangle on the given index
*/
def draw(index: Int, color: Color): Unit = {
private def paint(): Unit = {
if (blockSize != 0) {
paint()
updateBuffer((_: PixelBuffer[IntBuffer]) => {
// drawRect(e.lineNumber - 1, Filter.calcColor(e.value, filtersProperty.asScala.toSeq).darker().darker())
LPixelBuffer.drawRect(rawInts, index, shape.width.toInt, blockSize, color)
cleanBackground()
var i = 0
entries.forEach(e => {
if (e.lineNumber.equals(selectedLineNumberProperty.getValue())) {
LPixelBuffer.drawRect(rawInts, i, shape.width, blockSize, Color.YELLOW)
} else {
LPixelBuffer.drawRect(rawInts, i, shape.width, blockSize, Filter.calcColor(e.value, filters))
}
i = i + 1
})
shape
})
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ class LogFileTab(val pathAsString: String
op
}

private val chunkListView = ChunkListView(filteredList, mutLogFileSettings)

// display text to the right
private val logTextView = new LogTextView(mutLogFileSettings, filteredList)

// graphical display to the left
private val chunkListView = ChunkListView(filteredList, mutLogFileSettings, logTextView.selectLogEntry)


// start listener declarations
private lazy val scrollToEndEventListener: InvalidationListener = (_: Observable) => {
chunkListView.scrollTo(chunkListView.getItems.size())
Expand Down
43 changes: 17 additions & 26 deletions app/src/main/scala/app/logorrr/views/text/LogTextView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package app.logorrr.views.text

import app.logorrr.conf.mut.MutLogFileSettings
import app.logorrr.model.LogEntry
import app.logorrr.util.{CanLog, ClipBoardUtils, JfxUtils}
import app.logorrr.util.{CanLog, JfxUtils}
import javafx.beans.value.ChangeListener
import javafx.collections.transformation.FilteredList
import javafx.scene.control._
Expand All @@ -23,42 +23,33 @@ object LogTextView {

class LogTextView(mutLogFileSettings: MutLogFileSettings
, filteredList: FilteredList[LogEntry]) extends ListView[LogEntry] with CanLog {
/** 'pragmatic way' to determine width of max elems in this view */
val maxLength: Int = filteredList.size().toString.length


private val selectedLineNumberListener: ChangeListener[Number] = JfxUtils.onNew((n: Number) => {
Option(getItems.filtered((t: LogEntry) => t.lineNumber == n.intValue()).get(0)) match {
case Some(value) =>
val relativeIndex = getItems.indexOf(value)
getSelectionModel.select(relativeIndex)
scrollTo(relativeIndex - ((getHeight / LogTextView.fixedCellSize) / 2).toInt)
case None =>
}
})

init()

/**
*
*/
def init(): Unit = {
getStyleClass.add("dense")
setItems(filteredList)
val i = mutLogFileSettings.selectedLineNumberProperty.get()
getSelectionModel.select(i)
getSelectionModel.select(mutLogFileSettings.selectedLineNumberProperty.get())

getSelectionModel.selectedIndexProperty().addListener(JfxUtils.onNew({ i: Number => {
mutLogFileSettings.selectedLineNumberProperty.removeListener(selectedLineNumberListener)
mutLogFileSettings.setSelectedLineNumber(i.intValue())
mutLogFileSettings.selectedLineNumberProperty.addListener(selectedLineNumberListener)
}
}))
getSelectionModel.selectedItemProperty().addListener(JfxUtils.onNew[LogEntry](e => mutLogFileSettings.setSelectedLineNumber(e.lineNumber)))
setCellFactory((_: ListView[LogEntry]) => new LogEntryListCell())
mutLogFileSettings.selectedLineNumberProperty.addListener(selectedLineNumberListener)

}

/** 'pragmatic way' to determine width of max elems in this view */
def maxLength: Int = filteredList.size().toString.length

def selectLogEntry(logEntry: LogEntry): Unit = {
getSelectionModel.select(logEntry)
val relativeIndex = getItems.indexOf(logEntry)
getSelectionModel.select(relativeIndex)
val cellHeight = lookup(".list-cell").getBoundsInLocal.getHeight
val visibleItemCount = (getHeight / cellHeight).asInstanceOf[Int]
val idx = if (relativeIndex - visibleItemCount / 2 <= 0) 0 else relativeIndex - visibleItemCount / 2
scrollTo(idx)
}


class LogEntryListCell extends ListCell[LogEntry] {
styleProperty().bind(mutLogFileSettings.fontStyleBinding)
setGraphic(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import org.scalatest.wordspec.AnyWordSpec

class BlockImageSpec extends AnyWordSpec {

"BlockImage.indexOf" should {
".a" in assert(BlockImage.indexOf(0, 0, 100, 1000) == 0)
".b" in assert(BlockImage.indexOf(0, 0, 10, 100) == 0)
".c" in assert(BlockImage.indexOf(11, 0, 10, 100) == 1)
".d" in assert(BlockImage.indexOf(99, 0, 10, 100) == 9)
".f" in assert(BlockImage.indexOf(0, 11, 10, 100) == 10)
".e" in assert(BlockImage.indexOf(99, 99, 10, 100) == 99)
}

"BlockImage.calcVirtualHeight" should {
"sc0" in assert(BlockImage.calcVirtualHeight(1, 7, 10, 0) == 0)
"sc1" in assert(BlockImage.calcVirtualHeight(1, 7, 10, 1) == 7)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class ChunkListTestApp extends Application with CanLog {
, new SimpleIntegerProperty(selectedLineNumber)
, new SimpleIntegerProperty(blockSize)
, filtersProperty
, new SimpleDoubleProperty(dividerPosition))
, new SimpleDoubleProperty(dividerPosition)
, e => ())
clv.addListeners()
val sp = new SplitPane(clv, new BorderPane(new Label("Test")))

Expand Down

0 comments on commit 08c5c8e

Please sign in to comment.