From 9e476630279a7844b1ee3984c21084c0eb725237 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Fri, 5 Apr 2024 09:04:42 -0700
Subject: [PATCH] Update flatlaf to v3.4.1 (#153)
* Fix some UI bugs, use new split pane expandable side feature
---
gradle/libs.versions.toml | 2 +-
.../inductiveautomation/kindling/MainPanel.kt | 8 +-
.../kindling/idb/generic/DBMetaDataTree.kt | 47 ++--
.../kindling/idb/generic/GenericView.kt | 249 +++++++++---------
.../kindling/idb/metrics/MetricCard.kt | 3 +-
.../kindling/log/LogPanel.kt | 2 +-
.../kindling/log/MDCPanel.kt | 10 +-
.../kindling/log/TimePanel.kt | 25 +-
.../kindling/utils/Components.kt | 50 ++--
.../kindling/xml/XmlViewer.kt | 4 +-
.../xml/logback/SelectedLoggerCard.kt | 3 +-
.../kindling/zip/views/gwbk/GwbkStatsView.kt | 3 +-
.../resources/icons/bx-subdirectory-left.svg | 3 +
13 files changed, 220 insertions(+), 189 deletions(-)
create mode 100644 src/main/resources/icons/bx-subdirectory-left.svg
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 910a5034..b7b5a506 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,7 +2,7 @@
java = "21"
kotlin = "1.9.22"
coroutines = "1.8.0"
-flatlaf = "3.4"
+flatlaf = "3.4.1"
kotest = "5.8.1"
ignition = "8.1.20"
jackson = "2.17.0"
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/MainPanel.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/MainPanel.kt
index f59ecd31..c5ef95e8 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/MainPanel.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/MainPanel.kt
@@ -136,7 +136,7 @@ class MainPanel : JPanel(MigLayout("ins 6, fill, hidemode 3")) {
private val landingPanel = JPanel(MigLayout("ins 0, fillx", "[center, grow]")).apply {
add(
JLabel("Open...").apply {
- font = font.deriveFont(24F)
+ putClientProperty("FlatLaf.styleClass", "h1")
},
)
for (tools in Tool.sortedByTitle.chunked(3)) {
@@ -148,10 +148,8 @@ class MainPanel : JPanel(MigLayout("ins 6, fill, hidemode 3")) {
}
private fun toolTile(tool: Tool): JButton {
- return JButton().apply {
- text = tool.title
- font = font.deriveFont(18F)
- icon = tool.icon.derive(2F)
+ return JButton(tool.title, tool.icon.derive(2F)).apply {
+ putClientProperty("FlatLaf.styleClass", "h2.regular")
iconTextGap = 20
verticalTextPosition = BOTTOM
horizontalTextPosition = CENTER
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/DBMetaDataTree.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/DBMetaDataTree.kt
index fdee555b..945b6738 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/DBMetaDataTree.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/DBMetaDataTree.kt
@@ -2,14 +2,10 @@ package io.github.inductiveautomation.kindling.idb.generic
import com.formdev.flatlaf.extras.FlatSVGIcon
import com.formdev.flatlaf.extras.components.FlatTree
-import com.jidesoft.swing.StyledLabelBuilder
import com.jidesoft.swing.TreeSearchable
-import com.jidesoft.tree.StyledTreeCellRenderer
import io.github.inductiveautomation.kindling.utils.asActionIcon
import io.github.inductiveautomation.kindling.utils.toFileSizeLabel
-import java.awt.Font
-import javax.swing.JTree
-import javax.swing.UIManager
+import io.github.inductiveautomation.kindling.utils.treeCellRenderer
import javax.swing.tree.TreeModel
import javax.swing.tree.TreePath
import javax.swing.tree.TreeSelectionModel
@@ -21,36 +17,27 @@ class DBMetaDataTree(treeModel: TreeModel) : FlatTree() {
setShowsRootHandles(true)
selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
setCellRenderer(
- object : StyledTreeCellRenderer() {
- override fun customizeStyledLabel(tree: JTree, value: Any?, sel: Boolean, expanded: Boolean, leaf: Boolean, row: Int, focused: Boolean) {
- super.customizeStyledLabel(tree, value, sel, expanded, leaf, row, focused)
- clearStyleRanges()
-
- foreground = when {
- selected && focused -> UIManager.getColor("Tree.selectionForeground")
- selected -> UIManager.getColor("Tree.selectionInactiveForeground")
- else -> UIManager.getColor("Tree.textForeground")
+ treeCellRenderer { _, value, selected, _, _, _, hasFocus ->
+ when (value) {
+ is Table -> {
+ text = buildString {
+ append(value.name)
+ append(" ")
+ append("(${value.size.toFileSizeLabel()})")
+ }
+ icon = TABLE_ICON.asActionIcon(selected && hasFocus)
}
- when (value) {
- is Table -> {
- StyledLabelBuilder().apply {
- add(value.name)
- add(" ")
- add("(${value.size.toFileSizeLabel()})", Font.ITALIC)
- }.configure(this)
- icon = TABLE_ICON.asActionIcon(selected || focused)
- }
- is Column -> {
- StyledLabelBuilder().apply {
- add(value.name)
- add(" ")
- add(value.type.takeIf { it.isNotEmpty() } ?: "UNKNOWN", Font.ITALIC)
- }.configure(this)
- icon = COLUMN_ICON.asActionIcon(selected || focused)
+ is Column -> {
+ text = buildString {
+ append(value.name)
+ append(" ")
+ append(value.type.takeIf { it.isNotEmpty() } ?: "UNKNOWN")
}
+ icon = COLUMN_ICON.asActionIcon(selected && hasFocus)
}
}
+ this
},
)
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/GenericView.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/GenericView.kt
index 19c9783a..2ad2b6a9 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/GenericView.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/generic/GenericView.kt
@@ -1,7 +1,11 @@
package io.github.inductiveautomation.kindling.idb.generic
import com.formdev.flatlaf.extras.FlatSVGIcon
+import com.formdev.flatlaf.extras.components.FlatSplitPane
+import com.formdev.flatlaf.util.SystemInfo
import com.jidesoft.comparator.AlphanumComparator
+import io.github.inductiveautomation.kindling.core.Kindling.Preferences.UI.Theme
+import io.github.inductiveautomation.kindling.core.Theme.Companion.theme
import io.github.inductiveautomation.kindling.core.ToolPanel
import io.github.inductiveautomation.kindling.utils.Action
import io.github.inductiveautomation.kindling.utils.ButtonPanel
@@ -16,6 +20,9 @@ import io.github.inductiveautomation.kindling.utils.javaType
import io.github.inductiveautomation.kindling.utils.menuShortcutKeyMaskEx
import io.github.inductiveautomation.kindling.utils.toList
import net.miginfocom.swing.MigLayout
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea
+import org.fife.ui.rsyntaxtextarea.SyntaxConstants
+import org.fife.ui.rtextarea.RTextScrollPane
import java.awt.event.KeyEvent
import java.sql.Connection
import java.sql.JDBCType
@@ -28,7 +35,6 @@ import javax.swing.JButton
import javax.swing.JMenuItem
import javax.swing.JPanel
import javax.swing.JPopupMenu
-import javax.swing.JTextArea
import javax.swing.JToggleButton
import javax.swing.KeyStroke
import javax.swing.tree.DefaultTreeModel
@@ -85,10 +91,9 @@ class SortableTree(val tables: List
) {
val tree = DBMetaDataTree(DefaultTreeModel(root))
- private val sortActions: List =
- TableComparator.entries.map { tableComparator ->
- SortAction(tableComparator)
- }
+ private val sortActions: List = TableComparator.entries.map { tableComparator ->
+ SortAction(tableComparator)
+ }
inner class SortAction(comparator: TableComparator) : Action(
description = comparator.tooltip,
@@ -102,149 +107,156 @@ class SortableTree(val tables: List) {
var comparator: TableComparator by actionValue("tableComparator", comparator)
}
- private fun createSortButtons(): ButtonGroup =
- ButtonGroup().apply {
- for (sortAction in sortActions) {
- add(
- JToggleButton(
- Action(
- description = sortAction.description,
- icon = sortAction.icon,
- selected = sortAction.selected,
- ) { e ->
- sortAction.actionPerformed(e)
- },
- ),
- )
- }
+ private fun createSortButtons(): ButtonGroup = ButtonGroup().apply {
+ for (sortAction in sortActions) {
+ add(
+ JToggleButton(
+ Action(
+ description = sortAction.description,
+ icon = sortAction.icon,
+ selected = sortAction.selected,
+ ) { e ->
+ sortAction.actionPerformed(e)
+ },
+ ),
+ )
}
+ }
private val sortButtons = createSortButtons()
- val component =
- ButtonPanel(sortButtons).apply {
- add(FlatScrollPane(tree), "newline, push, grow")
- }
+ val component = ButtonPanel(sortButtons).apply {
+ add(FlatScrollPane(tree), "newline, push, grow")
+ }
}
class GenericView(connection: Connection) : ToolPanel("ins 0, fill, hidemode 3") {
@Suppress("SqlResolve")
- private val tables: List =
- connection
- .executeQuery("""SELECT name FROM main.sqlite_schema WHERE type = "table" ORDER BY name""")
- .toList { resultSet ->
- resultSet.getString(1)
- }.mapIndexed { i, tableName ->
- Table(
- name = tableName,
- _parent = { sortableTree.root },
- columns = connection
- .executeQuery("""PRAGMA table_xinfo("$tableName");""")
- .toList { resultSet ->
- Column(
- name = resultSet["name"],
- type = resultSet["type"],
- notNull = resultSet["notnull"],
- defaultValue = resultSet["dflt_value"],
- primaryKey = resultSet["pk"],
- hidden = resultSet["hidden"],
- _parent = { sortableTree.root.getChildAt(i) },
- )
- },
- size = connection
- .executeQuery("""SELECT SUM("pgsize") FROM "dbstat" WHERE name='$tableName'""")[1],
- )
- }
+ private val tables: List = connection
+ .executeQuery("""SELECT name FROM main.sqlite_schema WHERE type = "table" ORDER BY name""")
+ .toList { resultSet ->
+ resultSet.getString(1)
+ }.mapIndexed { i, tableName ->
+ Table(
+ name = tableName,
+ _parent = { sortableTree.root },
+ columns = connection
+ .executeQuery("""PRAGMA table_xinfo("$tableName");""")
+ .toList { resultSet ->
+ Column(
+ name = resultSet["name"],
+ type = resultSet["type"],
+ notNull = resultSet["notnull"],
+ defaultValue = resultSet["dflt_value"],
+ primaryKey = resultSet["pk"],
+ hidden = resultSet["hidden"],
+ _parent = { sortableTree.root.getChildAt(i) },
+ )
+ },
+ size = connection
+ .executeQuery("""SELECT SUM("pgsize") FROM "dbstat" WHERE name='$tableName'""")[1],
+ )
+ }
private val sortableTree = SortableTree(tables)
- private val query = JTextArea(0, 0)
+ private val query = RSyntaxTextArea().apply {
+ syntaxEditingStyle = SyntaxConstants.SYNTAX_STYLE_SQL
- private val execute =
- Action(name = "Execute") {
- results.result =
- if (!query.text.isNullOrEmpty()) {
- try {
- connection.executeQuery(query.text)
- .use { resultSet ->
- val columnCount = resultSet.metaData.columnCount
- val names = List(columnCount) { i -> resultSet.metaData.getColumnName(i + 1) }
- val types =
- List(columnCount) { i ->
- val timestamp =
- TIMESTAMP_COLUMN_NAMES.any {
- resultSet.metaData.getColumnName(i + 1).contains(it, true)
- }
+ theme = Theme.currentValue
- if (timestamp) {
- Timestamp::class.java
- } else {
- val sqlType = resultSet.metaData.getColumnType(i + 1)
- val jdbcType = JDBCType.valueOf(sqlType)
- jdbcType.javaType
- }
- }
+ Theme.addChangeListener { newTheme ->
+ theme = newTheme
+ }
+ }
- val data =
- resultSet.toList {
- List(columnCount) { i ->
- // SQLite stores booleans as ints, we'll use actual booleans to make things easier
- if (types[i] == Boolean::class.javaObjectType) {
- resultSet.getObject(i + 1) == 1
- } else {
- resultSet.getObject(i + 1)
- }
- }
- }
+ private val execute = Action(
+ name = "Execute",
+ description = "Execute (${if (SystemInfo.isMacOS) "⌘" else "Ctrl"} + Enter)",
+ icon = FlatSVGIcon("icons/bx-subdirectory-left.svg").asActionIcon(),
+ accelerator = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, menuShortcutKeyMaskEx),
+ ) {
+ results.result = if (!query.text.isNullOrEmpty()) {
+ try {
+ connection.executeQuery(query.text)
+ .use { resultSet ->
+ val columnCount = resultSet.metaData.columnCount
+ val names = List(columnCount) { i ->
+ resultSet.metaData.getColumnName(i + 1)
+ }
+ val types = List(columnCount) { i ->
+ val timestamp =
+ TIMESTAMP_COLUMN_NAMES.any {
+ resultSet.metaData.getColumnName(i + 1).contains(it, true)
+ }
- QueryResult.Success(names, types, data)
+ if (timestamp) {
+ Timestamp::class.java
+ } else {
+ val sqlType = resultSet.metaData.getColumnType(i + 1)
+ val jdbcType = JDBCType.valueOf(sqlType)
+ jdbcType.javaType
}
- } catch (e: Exception) {
- QueryResult.Error(e.message ?: "Error")
+ }
+
+ val data = resultSet.toList {
+ List(columnCount) { i ->
+ // SQLite stores booleans as ints, we'll use actual booleans to make things easier
+ if (types[i] == Boolean::class.javaObjectType) {
+ resultSet.getObject(i + 1) == 1
+ } else {
+ resultSet.getObject(i + 1)
+ }
+ }
+ }
+
+ QueryResult.Success(names, types, data)
}
- } else {
- QueryResult.Error("Enter a query in the text field above")
- }
+ } catch (e: Exception) {
+ QueryResult.Error(e.message ?: "Error")
+ }
+ } else {
+ QueryResult.Error("Enter a query in the text field above")
}
+ }
- private val queryPanel =
- JPanel(MigLayout("ins 0, fill")).apply {
- add(JButton(execute), "wrap")
- add(query, "push, grow")
- }
+ private val queryPanel = JPanel(MigLayout("ins 0, fill")).apply {
+ add(RTextScrollPane(query), "push, grow, wrap")
+ add(JButton(execute), "ax right, wrap")
+ }
private val results = ResultsPanel()
init {
val ctrlEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, menuShortcutKeyMaskEx)
getInputMap(WHEN_IN_FOCUSED_WINDOW).put(ctrlEnter, "execute")
+ query.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(ctrlEnter, "execute")
actionMap.put("execute", execute)
+ query.actionMap.put("execute", execute)
sortableTree.tree.attachPopupMenu { event ->
val path = getClosestPathForLocation(event.x, event.y)
when (val node = path?.lastPathComponent) {
- is Table ->
- JPopupMenu().apply {
- add(
- JMenuItem(
- Action("SELECT * FROM ${node.name}") {
- query.text = "SELECT * FROM ${node.name};"
- },
- ),
- )
- }
+ is Table -> JPopupMenu().apply {
+ add(
+ JMenuItem(
+ Action("SELECT * FROM ${node.name}") {
+ query.text = "SELECT * FROM ${node.name};"
+ },
+ ),
+ )
+ }
- is Column ->
- JPopupMenu().apply {
- val table = path.parentPath.lastPathComponent as Table
- add(
- JMenuItem(
- Action("SELECT ${node.name} FROM ${table.name}") {
- query.text = "SELECT ${node.name} FROM ${table.name}"
- },
- ),
- )
- }
+ is Column -> JPopupMenu().apply {
+ val table = path.parentPath.lastPathComponent as Table
+ add(
+ JMenuItem(
+ Action("SELECT ${node.name} FROM ${table.name}") {
+ query.text = "SELECT ${node.name} FROM ${table.name}"
+ },
+ ),
+ )
+ }
else -> null
}
@@ -254,9 +266,10 @@ class GenericView(connection: Connection) : ToolPanel("ins 0, fill, hidemode 3")
HorizontalSplitPane(
sortableTree.component,
VerticalSplitPane(
- FlatScrollPane(queryPanel),
+ queryPanel,
results,
resizeWeight = 0.2,
+ expandableSide = FlatSplitPane.ExpandableSide.both,
),
resizeWeight = 0.1,
),
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/metrics/MetricCard.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/metrics/MetricCard.kt
index f374bbf4..7a00079a 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/idb/metrics/MetricCard.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/idb/metrics/MetricCard.kt
@@ -13,7 +13,6 @@ import org.jfree.chart.annotations.XYLineAnnotation
import org.jfree.data.statistics.Regression
import org.jfree.data.xy.XYDataset
import java.awt.BasicStroke
-import java.awt.Font
import java.text.DecimalFormat
import java.text.FieldPosition
import java.text.NumberFormat
@@ -60,7 +59,7 @@ class MetricCard(val metric: Metric, data: List) : JPanel(MigLayout(
init {
add(
JLabel(metric.name, CENTER).apply {
- font = font.deriveFont(Font.BOLD, 14.0F)
+ putClientProperty("FlatLaf.styleClass", "h3")
},
"span, pushx, growx",
)
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/log/LogPanel.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/log/LogPanel.kt
index d4e86b58..d2408d85 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/log/LogPanel.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/log/LogPanel.kt
@@ -198,7 +198,7 @@ class LogPanel(
VerticalSplitPane(
HorizontalSplitPane(
sidebar,
- JPanel(MigLayout("fill")).apply {
+ JPanel(MigLayout("ins 0, fill")).apply {
add(header, "wrap, growx")
add(tableScrollPane, "grow, push")
},
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/log/MDCPanel.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/log/MDCPanel.kt
index 21acd468..eb96f9ab 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/log/MDCPanel.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/log/MDCPanel.kt
@@ -134,6 +134,7 @@ internal class MDCPanel(events: List) : FilterPanel()
}
private val removeFilter = Action(
+ name = "Remove",
description = "Remove Selected Filter",
icon = FlatSVGIcon("icons/bx-minus.svg").asActionIcon(),
) {
@@ -156,7 +157,7 @@ internal class MDCPanel(events: List) : FilterPanel()
}
private val removeAllFilters = Action(
- name = "Clear",
+ name = "Clear All",
description = "Remove All Filters",
icon = FlatSVGIcon("icons/bx-x.svg").asActionIcon(),
) {
@@ -200,7 +201,12 @@ internal class MDCPanel(events: List) : FilterPanel()
add(keyCombo, "growx, wrap, wmax 100%")
add(valueCombo, "growx, wrap, wmax 100%")
add(JButton(addFilter), "align right, split")
- add(JButton(removeFilter), "gapx 2")
+ add(
+ JButton(removeFilter).apply {
+ hideActionText = true
+ },
+ "gapx 2",
+ )
add(FlatScrollPane(filterTable), "newline, pushy, grow")
add(JButton(removeAllFilters), "align right, newline")
}
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/log/TimePanel.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/log/TimePanel.kt
index 49ad1034..9ffd3a7a 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/log/TimePanel.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/log/TimePanel.kt
@@ -51,6 +51,7 @@ import javax.swing.SpinnerNumberModel
import javax.swing.SwingConstants
import javax.swing.UIManager
import javax.swing.border.LineBorder
+import kotlin.math.absoluteValue
internal class TimePanel(
data: List,
@@ -130,7 +131,8 @@ internal class TimePanel(
private fun selectTime(timeToSelect: Instant) {
val table = containingLogPanel?.table ?: return
- val modelIndex = (table.model as LogsModel<*>).data.indexOfFirst { it.timestamp.truncatedTo(ChronoUnit.MINUTES) == timeToSelect }
+ val modelIndex = (table.model as LogsModel<*>).data
+ .indexOfFirst { it.timestamp.truncatedTo(ChronoUnit.MINUTES) == timeToSelect }
if (modelIndex == -1) return
val viewIndex = table.convertRowIndexToView(modelIndex)
@@ -313,10 +315,20 @@ class DateTimeSelector(
for (amount in listOf(-30L, -15, -5, -1, 1L, 5, 15, 30)) {
add(
FlatButton().apply {
- action =
- Action("%+d".format(amount)) {
- time = time.plusSeconds(amount * 60)
- }
+ action = Action(
+ name = "%+d".format(amount),
+ description = buildString {
+ append(if (amount > 0) "Add" else "Subtract")
+ append(" ")
+ append(amount.absoluteValue)
+ append(" minute")
+ if (amount.absoluteValue > 1) {
+ append("s")
+ }
+ },
+ ) {
+ time = time.plusSeconds(amount * 60)
+ }
margin = Insets(1, 1, 1, 1)
},
"w 12.5%, sgx",
@@ -449,7 +461,8 @@ private object DensityColumns : ColumnList() {
private val minuteFormatter: DateTimeFormatter
get() {
if (!this::_formatter.isInitialized) {
- _formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm").withZone(LogViewer.SelectedTimeZone.currentValue)
+ _formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm")
+ .withZone(LogViewer.SelectedTimeZone.currentValue)
}
if (_formatter.zone != LogViewer.SelectedTimeZone.currentValue) {
_formatter = _formatter.withZone(LogViewer.SelectedTimeZone.currentValue)
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/utils/Components.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/utils/Components.kt
index 4f0c1f99..b59ce427 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/utils/Components.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/utils/Components.kt
@@ -5,6 +5,8 @@ package io.github.inductiveautomation.kindling.utils
import com.formdev.flatlaf.FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING
import com.formdev.flatlaf.FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE
import com.formdev.flatlaf.extras.components.FlatScrollPane
+import com.formdev.flatlaf.extras.components.FlatSplitPane
+import com.formdev.flatlaf.extras.components.FlatSplitPane.ExpandableSide
import com.formdev.flatlaf.util.SystemInfo
import com.jidesoft.swing.StyledLabel
import com.jidesoft.swing.StyledLabelBuilder
@@ -17,7 +19,6 @@ import javax.swing.ButtonGroup
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.JSplitPane
-import javax.swing.SwingConstants
import javax.swing.border.EmptyBorder
inline fun FlatScrollPane(
@@ -78,31 +79,44 @@ fun HorizontalSplitPane(
left: Component,
right: Component,
resizeWeight: Double = 0.5,
+ expandableSide: ExpandableSide = ExpandableSide.right,
block: JSplitPane.() -> Unit = {},
-) = JSplitPane(SwingConstants.VERTICAL, left, right).apply {
- isOneTouchExpandable = true
- this.resizeWeight = resizeWeight
- addComponentListener(
- object : ComponentAdapter() {
- override fun componentShown(e: ComponentEvent?) {
- setDividerLocation(resizeWeight)
- }
- },
- )
-
- block()
-}
+) = createSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right, resizeWeight, expandableSide, block)
fun VerticalSplitPane(
top: Component,
bottom: Component,
resizeWeight: Double = 0.5,
+ // the top ("left") is the one that's allowed to expand
+ expandableSide: ExpandableSide = ExpandableSide.left,
block: JSplitPane.() -> Unit = {},
-) = JSplitPane(SwingConstants.HORIZONTAL, top, bottom).apply {
- isOneTouchExpandable = true
- this.resizeWeight = resizeWeight
+) = createSplitPane(JSplitPane.VERTICAL_SPLIT, top, bottom, resizeWeight, expandableSide, block)
- block()
+private fun createSplitPane(
+ orientation: Int,
+ left: Component,
+ right: Component,
+ resizeWeight: Double,
+ expandableSide: ExpandableSide,
+ block: JSplitPane.() -> Unit,
+): FlatSplitPane {
+ return FlatSplitPane().apply {
+ this.orientation = orientation
+ this.leftComponent = left
+ this.rightComponent = right
+ this.isOneTouchExpandable = true
+ this.expandableSide = expandableSide
+ this.resizeWeight = resizeWeight
+ addComponentListener(
+ object : ComponentAdapter() {
+ override fun componentShown(e: ComponentEvent?) {
+ setDividerLocation(resizeWeight)
+ }
+ },
+ )
+
+ block()
+ }
}
/**
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/xml/XmlViewer.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/xml/XmlViewer.kt
index 40b804fd..b85e5db3 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/xml/XmlViewer.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/xml/XmlViewer.kt
@@ -16,8 +16,8 @@ internal class XmlViewer(file: List) : JPanel(MigLayout("ins 6, fill, hi
syntaxEditingStyle = "text/xml"
theme = Theme.currentValue
- Theme.addChangeListener {
- theme = Theme.currentValue
+ Theme.addChangeListener { newValue ->
+ theme = newValue
}
},
),
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/xml/logback/SelectedLoggerCard.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/xml/logback/SelectedLoggerCard.kt
index a6075579..e4cc6c3b 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/xml/logback/SelectedLoggerCard.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/xml/logback/SelectedLoggerCard.kt
@@ -2,7 +2,6 @@ package io.github.inductiveautomation.kindling.xml.logback
import com.formdev.flatlaf.extras.FlatSVGIcon
import net.miginfocom.swing.MigLayout
-import java.awt.Font
import java.awt.event.ItemEvent
import javax.swing.JButton
import javax.swing.JCheckBox
@@ -71,7 +70,7 @@ internal class SelectedLoggerCard(
add(
JLabel(logger.name).apply {
- font = font.deriveFont(Font.BOLD, 14F)
+ putClientProperty("FlatLaf.styleClass", "h3")
},
)
add(closeButton, "right, wrap")
diff --git a/src/main/kotlin/io/github/inductiveautomation/kindling/zip/views/gwbk/GwbkStatsView.kt b/src/main/kotlin/io/github/inductiveautomation/kindling/zip/views/gwbk/GwbkStatsView.kt
index 1d392238..adb7dc9c 100644
--- a/src/main/kotlin/io/github/inductiveautomation/kindling/zip/views/gwbk/GwbkStatsView.kt
+++ b/src/main/kotlin/io/github/inductiveautomation/kindling/zip/views/gwbk/GwbkStatsView.kt
@@ -16,7 +16,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.miginfocom.swing.MigLayout
-import java.awt.Font
import java.nio.file.Path
import java.nio.file.spi.FileSystemProvider
import javax.swing.Icon
@@ -52,7 +51,7 @@ class GwbkStatsView(
private infix fun StatisticCalculator.renderedWith(renderer: StatisticRenderer): JPanel {
val headerLabel = JLabel(renderer.title, renderer.icon, SwingConstants.LEFT).apply {
- font = font.deriveFont(Font.BOLD, 14F)
+ putClientProperty("FlatLaf.styleClass", "h3")
}
val subtitleLabel = JLabel()
val throbber = JLabel(FlatSVGIcon("icons/bx-loader-circle.svg"))
diff --git a/src/main/resources/icons/bx-subdirectory-left.svg b/src/main/resources/icons/bx-subdirectory-left.svg
new file mode 100644
index 00000000..e3e45e35
--- /dev/null
+++ b/src/main/resources/icons/bx-subdirectory-left.svg
@@ -0,0 +1,3 @@
+