
tornadofx.Nodes.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fx Show documentation
Show all versions of fx Show documentation
Lightweight JavaFX Framework for Kotlin
The newest version!
package tornadofx
import com.sun.javafx.scene.control.skin.TableColumnHeader
import javafx.beans.value.ObservableValue
import javafx.event.EventTarget
import javafx.scene.Node
import javafx.scene.Scene
import javafx.scene.control.*
import javafx.scene.input.InputEvent
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.input.MouseEvent
import javafx.scene.layout.GridPane
import javafx.scene.layout.Pane
import javafx.stage.Stage
import javafx.util.Callback
import kotlin.reflect.KClass
fun Node.hasClass(className: String) = styleClass.contains(className)
fun Node.addClass(className: String) = styleClass.add(className)
fun Node.removeClass(className: String) = styleClass.remove(className)
fun Node.toggleClass(className: String, predicate: Boolean) = if (predicate) addClass(className) else removeClass(className)
fun Scene.reloadStylesheets() {
val styles = stylesheets.toMutableList()
stylesheets.clear()
stylesheets.addAll(styles)
}
fun Stage.reloadStylesheetsOnFocus() {
focusedProperty().addListener { obs, old, new ->
if (new)
scene.reloadStylesheets()
}
}
fun Pane.reloadStylesheets() {
val styles = stylesheets.toMutableList()
stylesheets.clear()
stylesheets.addAll(styles)
}
infix fun Node.addTo(pane: Pane) = pane.children.add(this)
fun Pane.replaceChildren(vararg uiComponents: UIComponent) =
this.replaceChildren(*(uiComponents.map { it.root }.toTypedArray()))
fun Pane.replaceChildren(vararg node: Node) {
children.clear()
children.addAll(node)
}
operator fun ToolBar.plusAssign(uiComponent: UIComponent): Unit {
items.add(uiComponent.root)
}
operator fun ToolBar.plusAssign(node: Node): Unit {
items.add(node)
}
fun ToolBar.add(node: Node) = plusAssign(node)
inline fun ToolBar.add(type: KClass): Unit = plusAssign(find(type))
operator fun Pane.plusAssign(node: Node) {
children.add(node)
}
inline fun Pane.add(type: KClass) = plusAssign(find(type).root)
fun Pane.add(node: Node) = plusAssign(node)
operator fun Pane.plusAssign(type: KClass) = plusAssign(find(type).root)
operator fun Pane.plusAssign(view: UIComponent): Unit {
plusAssign(view.root)
}
val TableView.selectedItem: T
get() = this.selectionModel.selectedItem
val TreeView.selectedValue: T
get() = this.selectionModel.selectedItem.value
fun TableView.selectFirst() = selectionModel.selectFirst()
fun TreeView.selectFirst() = selectionModel.selectFirst()
val ListView.selectedItem: T
get() = selectionModel.selectedItem
fun TableView.onSelectionChange(func: (S?) -> Unit) =
selectionModel.selectedItemProperty().addListener({ observable, oldValue, newValue -> func(newValue) })
fun TableColumn.fixedWidth(width: Double): TableColumn {
minWidth = width
maxWidth = width
return this
}
inline fun TableColumn.cellFormat(crossinline formatter: (TableCell.(T) -> Unit)) {
cellFactory = Callback { column: TableColumn ->
object : TableCell() {
override fun updateItem(item: T, empty: Boolean) {
super.updateItem(item, empty)
if (item == null || empty) {
text = null
graphic = null
} else {
formatter(this, item)
}
}
}
}
}
inline fun TableView.addColumn(title: String, crossinline valueProvider: (TableColumn.CellDataFeatures) -> ObservableValue): TableColumn {
val column = TableColumn(title)
column.cellValueFactory = Callback { valueProvider(it) }
columns.add(column)
return column
}
inline fun ListView.cellFormat(crossinline formatter: (ListCell.(T) -> Unit)) {
cellFactory = Callback {
object : ListCell() {
override fun updateItem(item: T, empty: Boolean) {
super.updateItem(item, empty)
if (item == null || empty) {
text = null
graphic = null
} else {
formatter(this, item)
}
}
}
}
}
/**
* Execute action when the enter key is pressed or the mouse is clicked
* @param clickCount The number of mouse clicks to trigger the action
* *
* @param action The action to execute on select
*/
fun TableView.onUserSelect(clickCount: Int = 2, action: (T) -> Unit) {
val isSelected = { event: InputEvent ->
event.target.isInsideTableRow() && !selectionModel.isEmpty
}
addEventFilter(MouseEvent.MOUSE_CLICKED) { event ->
if (event.clickCount == clickCount && isSelected(event))
action(selectedItem)
}
addEventFilter(KeyEvent.KEY_PRESSED) { event ->
if (event.code == KeyCode.ENTER && !event.isMetaDown && isSelected(event))
action(selectedItem)
}
}
fun TreeView.onUserSelect(action: (T) -> Unit) {
selectionModel.selectedItemProperty().addListener { obs, old, new ->
if (new != null && new.value != null)
action(new.value)
}
}
fun TableView.onUserDelete(action: (T) -> Unit) {
addEventFilter(KeyEvent.KEY_PRESSED, { event ->
if (event.code == KeyCode.BACK_SPACE && selectedItem != null)
action(selectedItem)
})
}
fun ListView.onUserDelete(action: (T) -> Unit) {
addEventFilter(KeyEvent.KEY_PRESSED, { event ->
if (event.code == KeyCode.BACK_SPACE && selectedItem != null)
action(selectedItem)
})
}
fun TreeView.onUserDelete(action: (T) -> Unit) {
addEventFilter(KeyEvent.KEY_PRESSED, { event ->
if (event.code == KeyCode.BACK_SPACE && selectionModel.selectedItem?.value != null)
action(selectedValue)
})
}
/**
* Execute action when the enter key is pressed or the mouse is clicked
* @param clickCount The number of mouse clicks to trigger the action
* *
* @param action The runnable to execute on select
*/
fun ListView.onUserSelect(clickCount: Int = 2, action: (T) -> Unit) {
addEventFilter(MouseEvent.MOUSE_CLICKED) { event ->
if (event.clickCount == clickCount && selectedItem != null)
action(selectedItem)
}
addEventFilter(KeyEvent.KEY_PRESSED) { event ->
if (event.code == KeyCode.ENTER && !event.isMetaDown && selectedItem != null)
action(selectedItem)
}
}
/**
* Did the event occur inside a TableRow?
*/
fun EventTarget.isInsideTableRow(): Boolean {
if (this !is Node)
return false
if (this is TableColumnHeader)
return false
if (this is TableRow<*> || this is TableView<*>)
return true
if (this.parent != null)
return this.parent.isInsideTableRow()
return false
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy