From 0c4daf033b8279952b1bbf6db2205fa9757a98c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Ladst=C3=A4tter?= Date: Wed, 22 Nov 2023 20:00:03 +0100 Subject: [PATCH] #172: improves visual appearance of LogTextView; increases scrollbar size --- .../resources/app/logorrr/ChunkListView.css | 2 -- .../resources/app/logorrr/LogTextView.css | 30 +++++++++++++++++++ .../main/resources/app/logorrr/LogoRRR.css | 5 ++-- .../logorrr/conf/mut/MutLogFileSettings.scala | 2 +- .../scala/app/logorrr/util/MathUtil.scala | 5 ++-- .../app/logorrr/views/block/BlockImage.scala | 5 +++- .../logorrr/views/block/ChunkListCell.scala | 9 ++---- .../logorrr/views/block/ChunkListView.scala | 10 +++---- .../logorrr/views/block/LPixelBuffer.scala | 28 +++++++++-------- .../views/ops/DecreaseBlockSizeButton.scala | 12 ++++---- .../views/ops/IncreaseBlockSizeButton.scala | 10 +++---- .../app/logorrr/views/search/OpsToolBar.scala | 14 ++------- .../views/text/IncreaseTextSizeButton.scala | 5 ++-- .../app/logorrr/views/text/LogTextView.scala | 26 +++++++++++----- .../logorrr/views/text/LogTextViewLabel.scala | 14 ++++++--- .../app/logorrr/views/block/ChunkSpec.scala | 2 +- .../views/text/FilterCalculatorSpec.scala | 3 +- 17 files changed, 110 insertions(+), 72 deletions(-) create mode 100644 app/src/main/resources/app/logorrr/LogTextView.css diff --git a/app/src/main/resources/app/logorrr/ChunkListView.css b/app/src/main/resources/app/logorrr/ChunkListView.css index 830d873f..303bb878 100644 --- a/app/src/main/resources/app/logorrr/ChunkListView.css +++ b/app/src/main/resources/app/logorrr/ChunkListView.css @@ -3,10 +3,8 @@ } .list-cell { - -fx-background-color: -color-cell-bg; -fx-text-fill: -color-cell-fg; -fx-padding: 0; - -fx-padding: 0; -fx-border-width: 0; -fx-border-color: transparent; -fx-selection-bar: transparent; diff --git a/app/src/main/resources/app/logorrr/LogTextView.css b/app/src/main/resources/app/logorrr/LogTextView.css new file mode 100644 index 00000000..e67d9384 --- /dev/null +++ b/app/src/main/resources/app/logorrr/LogTextView.css @@ -0,0 +1,30 @@ +.list-view { + -fx-border-width: 0px; +} + +.list-cell { + -fx-text-fill: -color-cell-fg; + -fx-padding: 0; + -fx-border-width: 0; + -fx-border-color: transparent; + -fx-selection-bar: transparent; + -fx-background-color: transparent; +} + +.list-cell:odd { + -fx-background-color: transparent; +} + +.list-cell:even { + -fx-background-color: transparent; +} + +.list-cell:filled:selected { + -color-cell-fg: -color-cell-fg-selected-focused; + -fx-background-color: -color-logorrr-selected; +} + +.list-cell:filled:selected { + -color-cell-fg: -color-cell-fg-selected-focused; + -fx-background-color: -color-logorrr-selected; +} diff --git a/app/src/main/resources/app/logorrr/LogoRRR.css b/app/src/main/resources/app/logorrr/LogoRRR.css index aa36500b..bcadb572 100644 --- a/app/src/main/resources/app/logorrr/LogoRRR.css +++ b/app/src/main/resources/app/logorrr/LogoRRR.css @@ -1,5 +1,6 @@ /* based on primer-light.css from atlantafx */ .root { + -color-logorrr-selected: #ffff00; -color-dark: #1b1f24; -color-light: #ffffff; -color-base-0: #f6f8fa; @@ -3669,10 +3670,10 @@ Add support for NO_HEADER tweak in tables .table-view.no-header > .column-header -fx-padding: 0; } .scroll-bar:horizontal { - -fx-pref-height: 8px; + -fx-pref-height: 18px; } .scroll-bar:vertical { - -fx-pref-width: 8px; + -fx-pref-width: 18px; } .scroll-bar:hover, .scroll-bar:pressed, .scroll-bar:focused { -fx-opacity: 1; diff --git a/app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala b/app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala index 667ba560..c2b6033e 100644 --- a/app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala +++ b/app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala @@ -33,7 +33,7 @@ class MutLogFileSettings { private val firstOpenedProperty = new SimpleLongProperty() val selectedLineNumberProperty = new SimpleIntegerProperty() val dividerPositionProperty = new SimpleDoubleProperty() - private val fontSizeProperty = new SimpleIntegerProperty() + val fontSizeProperty = new SimpleIntegerProperty() val autoScrollActiveProperty = new SimpleBooleanProperty() val filtersProperty = new SimpleListProperty[Filter](FXCollections.observableArrayList()) diff --git a/app/src/main/scala/app/logorrr/util/MathUtil.scala b/app/src/main/scala/app/logorrr/util/MathUtil.scala index bfdb99bd..576cbd21 100644 --- a/app/src/main/scala/app/logorrr/util/MathUtil.scala +++ b/app/src/main/scala/app/logorrr/util/MathUtil.scala @@ -20,7 +20,9 @@ object MathUtil extends CanLog { , blockSizeProperty: SimpleIntegerProperty , entriesProperty: java.util.List[LogEntry] , listViewHeightProperty: ReadOnlyDoubleProperty): (Int, Int, Int) = { - val cols: Int = MathUtil.roundUp(widthProperty.get() / blockSizeProperty.get()) + val w = if (widthProperty.get() - BlockImage.ScrollBarWidth >= 0) widthProperty.get() - BlockImage.ScrollBarWidth else widthProperty.get() + + val cols: Int = MathUtil.roundUp(w / blockSizeProperty.get()) val rows: Int = if (entriesProperty.size() < cols) 1 else entriesProperty.size() / cols // per default, use 4 cells per visible page, align height with blocksize such that @@ -31,7 +33,6 @@ object MathUtil extends CanLog { // yields the best approximation of MaxHeight. val maxHeight = (BlockImage.MaxHeight / blockSizeProperty.get()) * blockSizeProperty.get() val height = Math.min(MathUtil.roundDown((listViewHeightProperty.get() / BlockImage.DefaultBlocksPerPage) / blockSizeProperty.get()) * blockSizeProperty.get(), maxHeight) - // val height: Int = Math.min(rows * blockSizeProperty.get(), BlockImage.MaxHeight) (cols, rows, height) } } diff --git a/app/src/main/scala/app/logorrr/views/block/BlockImage.scala b/app/src/main/scala/app/logorrr/views/block/BlockImage.scala index 3d3f1c08..18d0bc59 100644 --- a/app/src/main/scala/app/logorrr/views/block/BlockImage.scala +++ b/app/src/main/scala/app/logorrr/views/block/BlockImage.scala @@ -14,6 +14,9 @@ object BlockImage { val MaxHeight = 4096 + // width of Scrollbars + val ScrollBarWidth = 18 + /** defines how many table cells should be rendered per list height */ val DefaultBlocksPerPage = 4 @@ -65,7 +68,7 @@ class BlockImage(blockNumber: Int ) extends WritableImage(LPixelBuffer(blockNumber , Range(entries.get(0).lineNumber, entries.get(entries.size - 1).lineNumber) - , RectangularShape(widthProperty.get().toInt, heightProperty.get()) + , RectangularShape(if (widthProperty.get().toInt - BlockImage.ScrollBarWidth > 0) widthProperty.get().toInt - BlockImage.ScrollBarWidth else widthProperty.get().toInt, heightProperty.get()) , blockSizeProperty , entries , filtersProperty diff --git a/app/src/main/scala/app/logorrr/views/block/ChunkListCell.scala b/app/src/main/scala/app/logorrr/views/block/ChunkListCell.scala index 19769c7c..f9ef4e1c 100644 --- a/app/src/main/scala/app/logorrr/views/block/ChunkListCell.scala +++ b/app/src/main/scala/app/logorrr/views/block/ChunkListCell.scala @@ -15,11 +15,6 @@ import scala.util.Try /** * A listcell which can contain one or more log entries - * - * @param selectedLineNumberProperty - * @param widthProperty - * @param blockSizeProperty - * @param filtersProperty */ class ChunkListCell(selectedLineNumberProperty: SimpleIntegerProperty , widthProperty: ReadOnlyDoubleProperty @@ -30,11 +25,11 @@ class ChunkListCell(selectedLineNumberProperty: SimpleIntegerProperty // 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]() { + private val mouseEventHandler = new EventHandler[MouseEvent]() { override def handle(me: MouseEvent): Unit = { // 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) + val index = BlockImage.indexOf(me.getX.toInt, me.getY.toInt, blockSizeProperty.get, widthProperty.get.toInt - BlockImage.ScrollBarWidth) getEntryAt(getItem, index) match { case Some(value) => // set selected property such that the next repaint will highlight this entry diff --git a/app/src/main/scala/app/logorrr/views/block/ChunkListView.scala b/app/src/main/scala/app/logorrr/views/block/ChunkListView.scala index 88861c7e..eea373f8 100644 --- a/app/src/main/scala/app/logorrr/views/block/ChunkListView.scala +++ b/app/src/main/scala/app/logorrr/views/block/ChunkListView.scala @@ -49,7 +49,7 @@ class ChunkListView(val entries: ObservableList[LogEntry] var repaints = 0 - val repaintInvalidationListener = new InvalidationListener { + private val repaintInvalidationListener = new InvalidationListener { override def invalidated(observable: Observable): Unit = repaint() } @@ -124,12 +124,10 @@ class ChunkListView(val entries: ObservableList[LogEntry] def repaint(): Unit = JfxUtils.execOnUiThread { if (doRepaint) { repaints += 1 - timeR({ - updateItems() - refresh() - }, s"Repainted #$repaints") + updateItems() + refresh() } else { - val msg = s"Not repainted: width=${widthProperty().get()}, blockSize=${blockSizeProperty.get()}, height: ${heightProperty().get()}" + val msg = s"Not repainted. (width: ${widthProperty().get()}, blockSize: ${blockSizeProperty.get()}, height: ${heightProperty().get()})" logTrace(msg) } } diff --git a/app/src/main/scala/app/logorrr/views/block/LPixelBuffer.scala b/app/src/main/scala/app/logorrr/views/block/LPixelBuffer.scala index bb16ed5b..f055e83c 100644 --- a/app/src/main/scala/app/logorrr/views/block/LPixelBuffer.scala +++ b/app/src/main/scala/app/logorrr/views/block/LPixelBuffer.scala @@ -1,7 +1,7 @@ package app.logorrr.views.block import app.logorrr.model.LogEntry -import app.logorrr.util.{CanLog, ColorUtil, JfxUtils} +import app.logorrr.util.{CanLog, ColorUtil} import app.logorrr.views.search.Filter import javafx.beans.property.SimpleIntegerProperty import javafx.collections.ObservableList @@ -98,19 +98,21 @@ case class LPixelBuffer(blockNumber: Int // todo check visibility private def paint(): Unit = { if (blockSize != 0) { - updateBuffer((_: PixelBuffer[IntBuffer]) => { - 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 + if (shape.width > blockSize) { + updateBuffer((_: PixelBuffer[IntBuffer]) => { + 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 }) - shape - }) + } } } diff --git a/app/src/main/scala/app/logorrr/views/ops/DecreaseBlockSizeButton.scala b/app/src/main/scala/app/logorrr/views/ops/DecreaseBlockSizeButton.scala index adca16d1..a57b9592 100644 --- a/app/src/main/scala/app/logorrr/views/ops/DecreaseBlockSizeButton.scala +++ b/app/src/main/scala/app/logorrr/views/ops/DecreaseBlockSizeButton.scala @@ -6,14 +6,16 @@ import javafx.beans.property.SimpleIntegerProperty import javafx.scene.paint.Color class DecreaseBlockSizeButton(val blockSizeProperty: SimpleIntegerProperty) extends - RectButton(2 * OpsToolBar.blockSizeStep - , 2 * OpsToolBar.blockSizeStep - , Color.GRAY - , "decrease block size") with HasBlockSizeProperty { + RectButton(width = 8 + , height = 8 + , color = Color.GRAY + , tooltipMessage = "decrease block size") with HasBlockSizeProperty { setOnAction(_ => { - if (getBlockSize() - OpsToolBar.blockSizeStep > 0) { + if (getBlockSize() - OpsToolBar.blockSizeStep >= 2) { setBlockSize(getBlockSize() - OpsToolBar.blockSizeStep) + } else { + setBlockSize(2) } }) diff --git a/app/src/main/scala/app/logorrr/views/ops/IncreaseBlockSizeButton.scala b/app/src/main/scala/app/logorrr/views/ops/IncreaseBlockSizeButton.scala index 9271fe32..4ad7cdf4 100644 --- a/app/src/main/scala/app/logorrr/views/ops/IncreaseBlockSizeButton.scala +++ b/app/src/main/scala/app/logorrr/views/ops/IncreaseBlockSizeButton.scala @@ -6,13 +6,13 @@ import javafx.beans.property.SimpleIntegerProperty import javafx.scene.paint.Color class IncreaseBlockSizeButton(val blockSizeProperty: SimpleIntegerProperty) extends - RectButton(4 * OpsToolBar.blockSizeStep - , 4 * OpsToolBar.blockSizeStep - , Color.GRAY - , "increase block size") with HasBlockSizeProperty { + RectButton(width = 16 + , height = 16 + , color = Color.GRAY + , tooltipMessage = "increase block size") with HasBlockSizeProperty { setOnAction(_ => { - if (getBlockSize() + OpsToolBar.blockSizeStep < 20 * OpsToolBar.blockSizeStep) { + if (getBlockSize() + OpsToolBar.blockSizeStep < 70 * OpsToolBar.blockSizeStep) { setBlockSize(getBlockSize() + OpsToolBar.blockSizeStep) } }) diff --git a/app/src/main/scala/app/logorrr/views/search/OpsToolBar.scala b/app/src/main/scala/app/logorrr/views/search/OpsToolBar.scala index 6e9b3b58..809ff30e 100644 --- a/app/src/main/scala/app/logorrr/views/search/OpsToolBar.scala +++ b/app/src/main/scala/app/logorrr/views/search/OpsToolBar.scala @@ -18,19 +18,11 @@ import javafx.scene.input.{KeyCode, KeyEvent} object OpsToolBar { /** increment/decrement block size */ - val blockSizeStep = 4 + val blockSizeStep = 2 /** increment / decrement font size */ - val fontSizeStep = 2 - /* - private val BackgroundSelectedStyle: String = - """ - |-fx-background-color: CYAN; - |-fx-border-width: 1px 1px 1px 1px; - |-fx-border-color: BLUE; - |-fx-padding: 0px 0px 0px 3px; - |""".stripMargin - */ + val fontSizeStep = 1 + } /** diff --git a/app/src/main/scala/app/logorrr/views/text/IncreaseTextSizeButton.scala b/app/src/main/scala/app/logorrr/views/text/IncreaseTextSizeButton.scala index 4b5ace31..6c17c00b 100644 --- a/app/src/main/scala/app/logorrr/views/text/IncreaseTextSizeButton.scala +++ b/app/src/main/scala/app/logorrr/views/text/IncreaseTextSizeButton.scala @@ -6,13 +6,12 @@ import app.logorrr.views.search.OpsToolBar /** * UI element for changing text size * - * @param size size of 'T' icon - * @param eventHandler event which will be triggered upon click + * @param pathAsString to resolve current log file */ class IncreaseTextSizeButton(val pathAsString: String) extends TextSizeButton(16, "increase text size") { setOnAction(_ => { - if (getFontSize + OpsToolBar.fontSizeStep < 10 * OpsToolBar.fontSizeStep) { + if (getFontSize + OpsToolBar.fontSizeStep < 50 * OpsToolBar.fontSizeStep) { setFontSize(getFontSize + OpsToolBar.fontSizeStep) } }) diff --git a/app/src/main/scala/app/logorrr/views/text/LogTextView.scala b/app/src/main/scala/app/logorrr/views/text/LogTextView.scala index c3382246..c23b8dd7 100644 --- a/app/src/main/scala/app/logorrr/views/text/LogTextView.scala +++ b/app/src/main/scala/app/logorrr/views/text/LogTextView.scala @@ -27,13 +27,21 @@ class LogTextView(mutLogFileSettings: MutLogFileSettings init() def init(): Unit = { - getStyleClass.add("dense") + getStylesheets.add(getClass.getResource("/app/logorrr/LogTextView.css").toExternalForm) + setItems(filteredList) getSelectionModel.select(mutLogFileSettings.selectedLineNumberProperty.get()) - getSelectionModel.selectedItemProperty().addListener(JfxUtils.onNew[LogEntry](e => mutLogFileSettings.setSelectedLineNumber(e.lineNumber))) + getSelectionModel.selectedItemProperty().addListener(JfxUtils.onNew[LogEntry](e => { + Option(e) match { + case Some(value) => mutLogFileSettings.setSelectedLineNumber(value.lineNumber) + case None => logTrace("Selected item was null") + } + })) setCellFactory((_: ListView[LogEntry]) => new LogEntryListCell()) - + mutLogFileSettings.fontSizeProperty.addListener(JfxUtils.onNew[Number](n => { + refresh() // otherwise listview is not repainted correctly since calculation of the cellheight is broken atm + })) } /** 'pragmatic way' to determine width of max elems in this view */ @@ -43,7 +51,11 @@ class LogTextView(mutLogFileSettings: MutLogFileSettings getSelectionModel.select(logEntry) val relativeIndex = getItems.indexOf(logEntry) getSelectionModel.select(relativeIndex) - val cellHeight = lookup(".list-cell").getBoundsInLocal.getHeight + // font size dictates the height of a cell + // kind of a hack, has to be enough for the moment + val cellHeight = mutLogFileSettings.getFontSize + // to lookup the cell height, equally a hack + // 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) @@ -65,18 +77,16 @@ class LogTextView(mutLogFileSettings: MutLogFileSettings calculateLabel(e) case None => setGraphic(null) - setText(null) setContextMenu(null) } } private def calculateLabel(e: LogEntry): Unit = { - setText(null) - val entry = LogTextViewLabel(e , maxLength , mutLogFileSettings.filtersProperty.get().asScala.toSeq - , mutLogFileSettings.fontStyleBinding) + , mutLogFileSettings.fontStyleBinding + , mutLogFileSettings.fontSizeProperty) setGraphic(entry) ignoreAbove.setOnAction(_ => { val currPredicate = filteredList.getPredicate diff --git a/app/src/main/scala/app/logorrr/views/text/LogTextViewLabel.scala b/app/src/main/scala/app/logorrr/views/text/LogTextViewLabel.scala index 78cb4eea..4e291de9 100644 --- a/app/src/main/scala/app/logorrr/views/text/LogTextViewLabel.scala +++ b/app/src/main/scala/app/logorrr/views/text/LogTextViewLabel.scala @@ -3,6 +3,8 @@ package app.logorrr.views.text import app.logorrr.model.LogEntry import app.logorrr.views.search.Filter import javafx.beans.binding.StringBinding +import javafx.beans.property.IntegerProperty +import javafx.geometry.Pos import javafx.scene.control.Label import javafx.scene.layout._ import javafx.scene.paint.Color @@ -11,28 +13,32 @@ import javafx.scene.paint.Color * Represents a line in LogoRRR's TextView. * * A line consist of a line number to the left and the line contents to the right. - * - * @param e - * @param maxLength - * @param filters */ case class LogTextViewLabel(e: LogEntry , maxLength: Int , filters: Seq[Filter] , fontStyleBinding: StringBinding + , fontSizeProperty: IntegerProperty ) extends HBox { + setHeight(fontSizeProperty.get()) + setAlignment(Pos.CENTER_LEFT) + val stringsAndColor: Seq[(String, Color)] = FilterCalculator(e, filters).stringColorPairs val labels: Seq[Label] = stringsAndColor.map { case (text, color) => val l = LogoRRRLabel.mkL(text, color) + l.minHeightProperty().bind(heightProperty()) + l.maxHeightProperty().bind(heightProperty()) l.styleProperty().bind(fontStyleBinding) l } val lineNumberLabel: LineNumberLabel = { val l = LineNumberLabel(e.lineNumber, maxLength) + l.minHeightProperty().bind(heightProperty()) + l.maxHeightProperty().bind(heightProperty()) l.styleProperty().bind(fontStyleBinding) l } diff --git a/app/src/test/scala/app/logorrr/views/block/ChunkSpec.scala b/app/src/test/scala/app/logorrr/views/block/ChunkSpec.scala index 4932e8b6..36b3c506 100644 --- a/app/src/test/scala/app/logorrr/views/block/ChunkSpec.scala +++ b/app/src/test/scala/app/logorrr/views/block/ChunkSpec.scala @@ -57,7 +57,7 @@ class ChunkSpec extends AnyWordSpec { } // default chunk size is 4 "test default chunk size" in { - val chunks = mkChunks(1000, 100, 10, 1000) + val chunks = mkChunks(1000, 100 + BlockImage.ScrollBarWidth, 10, 1000) assert(chunks.size == 4) assert(chunks.forall(c => c.entries.size == 250)) assert(chunks.last.entries.get(chunks.last.entries.size - 1).lineNumber == 999) diff --git a/app/src/test/scala/app/logorrr/views/text/FilterCalculatorSpec.scala b/app/src/test/scala/app/logorrr/views/text/FilterCalculatorSpec.scala index c963a61d..eeb12687 100644 --- a/app/src/test/scala/app/logorrr/views/text/FilterCalculatorSpec.scala +++ b/app/src/test/scala/app/logorrr/views/text/FilterCalculatorSpec.scala @@ -4,6 +4,7 @@ import app.logorrr.conf.mut.FilterSpec import app.logorrr.model.LogEntry import app.logorrr.views.search.Filter import app.logorrr.{LogEntrySpec, LogoRRRSpec} +import javafx.beans.property.SimpleIntegerProperty import javafx.scene.paint.Color import org.scalacheck.{Gen, Prop} @@ -14,7 +15,7 @@ object FilterCalculatorSpec { e <- LogEntrySpec.gen maxLength <- Gen.posNum[Int] filters <- Gen.listOf(FilterSpec.gen) - } yield LogTextViewLabel(e, maxLength, filters, () => "") + } yield LogTextViewLabel(e, maxLength, filters, () => "", new SimpleIntegerProperty()) } class FilterCalculatorSpec extends LogoRRRSpec {