Tornadofx - JavaFX Framework for Kotlin

Overview

TornadoFX Logo

TornadoFX

JavaFX Framework for Kotlin

Travis CI Maven Central Apache License

Important: TornadoFX is not yet compatible with Java 9/10

Oracle is intending to decouple JavaFX from the JDK. We will wait until the decoupled JavaFX is available and stable before upgrading TornadoFX to support it. As of now there is little value and significant effort involved in updating to JDK 9/10, while there will be an enormous value in updating to the decoupled version.

Features

  • Supports both MVC, MVP and their derivatives
  • Dependency injection
  • Type safe GUI builders
  • Type safe CSS builders
  • First class FXML support
  • Async task execution
  • EventBus with thread targeting
  • Hot reload of Views and Stylesheets
  • OSGi support
  • REST client with automatic JSON conversion
  • Zero config, no XML, no annotations

Important version note

TornadoFX requires Kotlin 1.1.2 and jvmTarget 1.8. Make sure you update your IDE plugins (Kotlin + TornadoFX).

After updating IntelliJ IDEA, make sure your Kotlin target version is 1.1 (Project Settings -> Modules -> Kotlin -> Language Version / API Version)

Remember to update your build system to configure the jvmTarget as well.

For Maven, you add the following configuration block to kotlin-maven-plugin:

<configuration>
    <jvmTarget>1.8jvmTarget>
configuration>

For Gradle, it means configuring the kotlinOptions of the Kotlin compilation task:

compileKotlin {
    kotlinOptions.jvmTarget= "1.8"
}

Failing to do so will yield errors about the compiler not being able to inline certain calls.

You also need a full rebuild of your code after a version upgrade. If you run into trouble, try to clean caches and restart IDEA (File -> Invalidate caches / Restart).

Getting started

Generate a quickstart application with Maven

mvn archetype:generate -DarchetypeGroupId=no.tornado \
  -DarchetypeArtifactId=tornadofx-quickstart-archetype \
  -DarchetypeVersion=1.7.20

Add TornadoFX to your project

Maven

<dependency>
    <groupId>no.tornadogroupId>
    <artifactId>tornadofxartifactId>
    <version>1.7.20version>
dependency>

Gradle

implementation 'no.tornado:tornadofx:1.7.20'

Snapshots are published to Sonatype

Configure your build environment to use snapshots if you want to try out the latest features:

 <repositories>
   <repository>
     <id>snapshots-repoid>
     <url>https://oss.sonatype.org/content/repositories/snapshotsurl>
     <releases><enabled>falseenabled>releases>
     <snapshots><enabled>trueenabled>snapshots>
   repository>
 repositories>

Snapshots are published every day at GMT 16:00 if there has been any changes.

What does it look like? (Code snippets)

Create a View

class HelloWorld : View() {
    override val root = hbox {
        label("Hello world")
    }
}

Start your application and show the primary View and add a type safe stylesheet

import javafx.scene.text.FontWeight
import tornadofx.*

class HelloWorldApp : App(HelloWorld::class, Styles::class)

class Styles : Stylesheet() {
    init {
        label {
            fontSize = 20.px
            fontWeight = FontWeight.BOLD
            backgroundColor += c("#cecece")
        }    
    }    
}

Start app and load a type safe stylesheet

Use Type Safe Builders to quickly create complex user interfaces

class MyView : View() {
    private val persons = FXCollections.observableArrayList(
            Person(1, "Samantha Stuart", LocalDate.of(1981,12,4)),
            Person(2, "Tom Marks", LocalDate.of(2001,1,23)),
            Person(3, "Stuart Gills", LocalDate.of(1989,5,23)),
            Person(3, "Nicole Williams", LocalDate.of(1998,8,11))
    )

    override val root = tableview(persons) {
        column("ID", Person::id)
        column("Name", Person::name)
        column("Birthday", Person::birthday)
        column("Age", Person::age)
        columnResizePolicy = SmartResize.POLICY
    }
}

RENDERED UI

Create a Customer model object that can be converted to and from JSON and exposes both a JavaFX Property and getter/setter pairs:

import tornadofx.getValue
import tornadofx.setValue

class Customer : JsonModel {
    val idProperty = SimpleIntegerProperty()
    var id by idProperty

    val nameProperty = SimpleStringProperty()
    var name by nameProperty

    override fun updateModel(json: JsonObject) {
        with(json) {
            id = int("id") ?: 0
            name = string("name")
        }
    }

    override fun toJSON(json: JsonBuilder) {
        with(json) {
            add("id", id)
            add("name", name)
        }
    }
}

Create a controller which downloads a JSON list of customers with the REST api:

class HelloWorldController : Controller() {
    val api : Rest by inject()
    
    fun loadCustomers(): ObservableList<Customer> = 
        api.get("customers").list().toModel() 
}

Configure the REST API with a base URI and Basic Authentication:

with (api) {
    baseURI = "http://contoso.com/api"
    setBasicAuth("user", "secret")
}

Load customers in the background and update a TableView on the UI thread:

runAsync {
    controller.loadCustomers()
} ui {
    customerTable.items = it
}

Load customers and apply to table declaratively:

customerTable.asyncItems { controller.loadCustomers() }

Define a type safe CSS stylesheet:

class Styles : Stylesheet() {
    companion object {
        // Define css classes
        val heading by cssclass()
        
        // Define colors
        val mainColor = c("#bdbd22")
    }

    init {
        heading {
            textFill = mainColor
            fontSize = 20.px
            fontWeight = BOLD
        }
        
        button {
            padding = box(10.px, 20.px)
            fontWeight = BOLD
        }

        val flat = mixin {
            backgroundInsets += box(0.px)
            borderColor += box(Color.DARKGRAY)
        }

        s(button, textInput) {
            +flat
        }
    }
}

Create an HBox with a Label and a TextField with type safe builders:

hbox {
    label("Hello world") {
        addClass(heading)
    }
    
    textfield {
        promptText = "Enter your name"
    }
}

Get and set per component configuration settings:

// set prefWidth from setting or default to 200.0
node.prefWidth(config.double("width", 200.0))

// set username and age, then save
with (config) {
    set("username", "john")
    set("age", 30)
    save()
}

Create a Fragment instead of a View. A Fragment is not a Singleton like View is, so you will create a new instance and you can reuse the Fragment in multiple ui locations simultaneously.

class MyFragment : Fragment() {
    override val root = hbox {
    }
}

Open it in a Modal Window:

find<MyFragment>().openModal()

Lookup and embed a View inside another Pane in one go

add<MyFragment>()

Inject a View and embed inside another Pane

val myView: MyView by inject()
 
init {
    root.add(myFragment)
}

Swap a View for another (change Scene root or embedded View)

(ViewTransition.Slide(0.3.seconds, Direction.LEFT) } }">
button("Go to next page") {
    action {
        replaceWith<PageTwo>(ViewTransition.Slide(0.3.seconds, Direction.LEFT)
    }
}

Open a View in an internal window over the current scene graph

() } }">
button("Open") {
    action {
        openInternalWindow<MyOtherView>()
    }
}
Comments
  • ViewModel / Validation (prev. ModelWrapper)

    ViewModel / Validation (prev. ModelWrapper)

    PR for easier code review/design discussion.

    There's quite a bit of outdated things in there and things I wasn't sure if it makes sense to keep them. I just didn't want to trash something that may turn out to be actually useful. You can probable skip looking at all the PropertyField implementations, because I think the GenericPropertyField (gonna rename that) is the way forward, so at the end we'd have PropertyFieldImpl, ListPropertyFieldImpl and SetPropertyFieldImpl. I've overloaded the String-field() methods quite a lot with several slightly different versions and explained the reasoning behind them. Those that are worth keeping would then also be added to the Number/Object/List/Set field() methods.

    At the end of the file there are several extension methods and ViewModel classes that are just things I tried out and that still need to be reworked somewhat. ViewSingleModel, although badly named, is probably the most useful thing there.

    I'm quite confident that isDifferent and isDirty ReadOnlyBooleanProperties are worth implementing, but a lot less sure whether or not validator/isValid is a good idea.

    Next up I'd unify the PropertyField implementations as explained above, implement the ReadOnlyBooleanProperties and generally rename/clean-up things.

    Comments/Suggestions are greatly appreciated. As this is refactored from the Java implementation and no clean-room design by an experienced Kotlin developer, there may be some things that could be done differently and, if you have doubts regarding the overall design, we can always start from a clean slate.

    opened by johnp 107
  • CSS Splitting Bug

    CSS Splitting Bug

    I'm not sure why I didn't notice this before, but there is a bug in the way CSS comma separated selectors are split. For example:

    s("A, B") {
        s("C, D") {
            textFill = c("green")
        }
    }
    

    should produce:

    A C, B C, A D, B D {
        -fx-text-fill: rgba(0, 128, 0, 1);
    }
    

    but instead produces:

    AC, B C, AD, B D {
        -fx-text-fill: rgba(0, 128, 0, 1);
    }
    

    (notice the lack of space after A both times).

    This has to do with the fact that the , immediately follows A when stored. A naive solution would be to just add a space after splitting the string, but that would break in the following case:

    s("A, B") {
        +s("C, D") {
            textFill = c("green")
        }
    }
    

    where you would get:

    A C, BC, A D, BD {
        -fx-text-fill: rgba(0, 128, 0, 1);
    }
    

    This could be fixed by doing checks on whether the value of current ends in a space, but I'm not sure how many more weird bugs are going to pop up in these kinds of corner cases, each of which requiring its own hack to get around.

    opened by ruckustboom 95
  • Some More Control Builders

    Some More Control Builders

    As I'm documenting the guide, I'm doing a sweep for more simple controls that probably should be added

    ~~ToggleButton~~ ~~RadioButton~~ ~~Slider~~ ~~TextFlow~~ ~~ChoiceBox~~ ~~PasswordField~~ ~~Separator~~ ~~HyperLink~~ ~~ColorPicker~~ ~~FileChooser~~ ~~Pagination~~ ~~HTMLEditor~~

    I know the TextFlow is a lesser-used control, but considering JavaFX lacks html formatting for label text (like Swing) it is helpful to format a string of text with different colors. I use this feature quite a bit to concatenate data with different conditional formatting rules.

    Let me know if we want to scratch any of these, and I'll work on adding whatever we wan)

    opened by thomasnield 54
  • Adopt Kotlin 1.1 DSL markers

    Adopt Kotlin 1.1 DSL markers

    opened by voddan 42
  • TreeTableView Builder

    TreeTableView Builder

    I'd like to explore streamlining the creation of TreeTableView with a builder in a similar manner as TableView. Not quite sure of the details yet but I imagine the nested structure nature would make it a a good candidate.

    Type: Enhancement 
    opened by thomasnield 40
  • TableView Builder?

    TableView Builder?

    Do you think it is possible to create a TableView builder? I think it would go nicely with the TableView extensions already present. I can put in a PR and try to work out the details if needed, unless somebody has a faster vision than me on how to do it.

    tableview {
            items = getMyItems()
            addColumn<ReportItem,String>("Category") { it.value.name }
            addColumn<ReportItem,BigDecimal>("Week") { it.value.weekTotal }
    }
    
    opened by thomasnield 38
  • Unable to load CSS Handler in OSGI run

    Unable to load CSS Handler in OSGI run

    I'm new to Kotlin, TornadoFX and OSGI, so I may be missing something that should be obvious. But...

    I'm using the osgi-run plugin (https://github.com/renatoathaydes/osgi-run) to make bundles and also to manage a felix container. When I run my application, I get this warning

    ____________________________
    Welcome to Apache Felix Gogo
    
    g! Waiting for JavaFX Runtime Startup.[Done]
    May 01, 2017 10:29:13 AM tornadofx.Stylesheet$Companion detectAndInstallUrlHandler
    INFO: Installing CSS url handler, since it was not picked up automatically
    May 01, 2017 10:29:13 AM tornadofx.Stylesheet$Companion detectAndInstallUrlHandler
    WARNING: Unable to install CSS url handler, type safe stylesheets might not work
    java.net.MalformedURLException: Unknown protocol: css
            at java.net.URL.<init>(URL.java:627)
            at java.net.URL.<init>(URL.java:490)
            at java.net.URL.<init>(URL.java:439)
            at tornadofx.Stylesheet$Companion.detectAndInstallUrlHandler(CSS.kt:445)
            at tornadofx.Stylesheet$Companion.access$detectAndInstallUrlHandler(CSS.kt:96)
            at tornadofx.Stylesheet.<clinit>(CSS.kt:428)
            at tornadofx.App.<init>(App.kt:71)
            at net.kirkstork.issues.MyApp.<init>(App.kt:21)
            at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
            at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
            at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at java.lang.Class.newInstance(Class.java:442)
            at tornadofx.osgi.impl.ApplicationListener.startDelegate(ApplicationListener.kt:105)
            at tornadofx.osgi.impl.ApplicationListener.startDelegateIfPossible(ApplicationListener.kt:87)
            at tornadofx.osgi.impl.ApplicationListener.<init>(ApplicationListener.kt:31)
            at tornadofx.osgi.impl.Activator.start(Activator.kt:14)
            at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:697)
            at org.apache.felix.framework.Felix.activateBundle(Felix.java:2226)
            at org.apache.felix.framework.Felix.startBundle(Felix.java:2144)
            at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1371)
            at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:308)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.IllegalStateException: Unknown protocol: css
            at org.apache.felix.framework.URLHandlersStreamHandlerProxy.parseURL(URLHandlersStreamHandlerProxy.java:373)
            at java.net.URL.<init>(URL.java:622)
            ... 22 more
    
    MyApp init...
    Waiting for Primary Stage to be initialized.[Done]
    

    My app is running, though and everything seems okay. (Until, of course, I try to use a stylesheet class.)

    I have a repo that reproduces this. https://github.com/kastork/tornadofx-css-osgi-reproducer

    Run it with gradle: ./gradlew runOsgi

    Looking at the code comments around this warning and exception, I see that it is an effort to deal with strange class loading situations. Perhaps OSGI is one of these situations. So I tried making the tornadofx jar an osgi 'system' package as mentioned here (https://github.com/renatoathaydes/osgi-run#system-libs).

    But when I do this, the JavaFX app never starts (although the bundle shows as an active bundle.

    So I'm not sure if I'm just doing things improperly with respect to the felix setup, or if there's some kind of bug in the TornadoFX start up logic.

    Any ideas?

    opened by kastork 37
  • onDestroy-type lifecycle event?

    onDestroy-type lifecycle event?

    Is it possible for FX.replaceComponent (and any other function that might be called by the framework) to execute an onDestroy type method on the View and Fragment being replaced?

    I use RxJava quite a bit, and it keeps a strong reference to its subscriber. Therefore, you have to explicitly unsubscribe from the observer before removing a View / Fragment or else you'll cause a memory leak. When you're manipulating things yourself it's not a problem, since you can notify the views that they need to drop their RxJava subscriptions.

    But, if you use the live reload features of tornadofx, you'll start leaking memory again, since it doesn't know anything about any clean-up logic that should be run when a View or Fragment is removed. Having something like an overridable 'onDestroy' on View / Fragment would let you perform the clean-up yourself when the framework calls FX.replaceComponent (or etc) for whatever reason.

    opened by radicaled 37
  • JDK 10/11 compatibility changes

    JDK 10/11 compatibility changes

    This PR fixes #794

    • For reflection used in AutoCompleteComboBoxSkin.kt and DataGrid.kt, an application depending on TornadoFX needs to pass --add-opens javafx.controls/javafx.scene.control.skin=ALL-UNNAMED when running the application.
    • I am using a Java class for ReflectionUtils because I was having issues changing the varargs parameter into Kotlin. If someone can help me with it, I would be glad to update it.
    JDK: 9 
    opened by abhinayagarwal 35
  • Integrate DI

    Integrate DI

    This is probably more a discussion piece then an issue or request. And it might get long :) so please bear with me. Disclaimer

    javafx and desktop development is even after 30 years still quite new to me, I usually write large scale backends.

    I am writing a javafx implementation of keepass. All communication is done using the Guava EventBus. This means that When you select a group (see image) an event is sent that is picked up by the tableview and so on. It works quite nice. During the writing of this I stumbled on Kotlin, was interested, so now part of it is in Kotlin, part in javafx. I am using fx-guice. I was looking at rewriting the whole ui part in kotlin, but I am looking at a decent way to implement guice into it.

    Is there going to be decent hook into DI (Guice or heaven forbid spring?)

    screenshot from 2016-04-10 21-09-01

    opened by ronsmits 28
  • Setting an Icon for All Views and Fragments

    Setting an Icon for All Views and Fragments

    Since TornadoFX manages all Views and Fragments, I wonder if there is an easy way to set a graphic icon for all of them. I don't think there is a direct way to do this with JavaFX.

    myStage.icons += Image("icon.png") 
    
    opened by thomasnield 28
  • Tornadofx with Spring security

    Tornadofx with Spring security

    Hello, I was implementing the application login for TornadoFx with Reactive Spring security. I have overridden the spring security methods.  While running the application lunch(MyApp), spring configuration classes were not initialising and beans.

    How to initialise the Spring configuration classes and beans at the start of the application.

    opened by venugopi26 0
  • Data Driven TreeView

    Data Driven TreeView

    Hello TornadoFx community!

    I was hoping to get some clarification on a point in the Guide w.r.t. a data drive TreeView. I'm having trouble getting this working, and am wondering what I might be missing.

    Here is my ViewModel:

    class ContactViewModel : ViewModel() {
    
        private val activeMapProperty = mapProperty(observableMapOf<String, ServiceAnnouncement>())
        private val activeProperty = listProperty(observableListOf<ServiceAnnouncement>())
        val active: ObservableList<ServiceAnnouncement> by activeProperty  // explicit type due to platform call
        
        init { 
            AddressBook.ContactAdded += ::contactAdded
            activeProperty.bind(nonNullObjectBinding(activeMapProperty) { observableListOf(values) } )
        }
        
        private fun contactAdded(sender: Any, contact: ServiceAnnouncement) {
            activeMapProperty.putIfAbsent(contact.uid, contact)
        }
    }
    

    And in my View class:

    class ContactTree : View() { 
        private val contactViewModel: ContactViewModel by inject()
        
        override val root: Parent = treeview<Any> {
            root = TreeItem("Active")
            root.isExpanded = true
    
            populate { parent ->
                when (val v = parent.value) {
                    "Active" -> contactViewModel.active
                    else -> null
                }
            }
    
            onUserSelect { println("$it") }
        }
    }
    

    From the Guide section on Data Driven TreeView:

    If the child list you return from populate is an ObservableList, any changes to that list will automatically be reflected in the TreeView. The populate function will be called for any new children that appears, and removed items will result in removed TreeItems as well.

    As you can see, my ContactViewModel::active property is type ObservableList<ServiceAnnouncement>, which meets the "if the child list you return is an ObservableList" criteria. And I was able to verify through the IntelliJ debugger that when ContactViewModel::contactAdded is called that all of activeMapProperty, activeProperty, and active reflect the update, but nothing happens in my UI.

    Any advice would be greatly appreciated!

    opened by toughstumpryan 1
  • Localization of german Double values

    Localization of german Double values

    Hello,

    i've built an app with tornadofx to save double values into a database with an editable tableview. Everything works fine so far, but since the customers are germans i'm trying to get the javafx.utils to parse "," instead of "." for double values.

    Is there actually any possibility or is it possible to add support for localized number formats? Setting a Locale on NumberFormat doesnt work, since the parsing happens within tornadofx.

    The actual error:

    java.lang.NumberFormatException: For input string: "7,5" at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043) at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.lang.Double.parseDouble(Double.java:538) at java.lang.Double.valueOf(Double.java:502) at javafx.util.converter.DoubleStringConverter.fromString(DoubleStringConverter.java:49) at javafx.util.converter.DoubleStringConverter.fromString(DoubleStringConverter.java:35) at javafx.scene.control.cell.CellUtils.lambda$createTextField$1(CellUtils.java:248)

    opened by chr1syy 0
  • TornadoFx stackpane overlapping with menubar

    TornadoFx stackpane overlapping with menubar

    Recently I am having trouble with my application with TornadoFx. The stackpane I created for drawing shape was overlapping the menubar and toolbar when I moved it by mouse. How can I solve this program? Thanks a lot. Below is my code:

    overlap

    class MainView : View("TornadoFX Zoom Test") {
        var canvas:  PannableCanvas by singleAssign()
        var stackPane: StackPane by singleAssign()
        var topCell = Group()
        override val root = vbox {
          menubar{
                menu("File") {
                    menu("Connect") {
                        item("Facebook")
                        item("Twitter")
                    }
                    item("Save")
                    item("Quit")
                }
                menu("Edit") {
                    item("Copy")
                    item("Paste")
                }
            }
    ```
    
            toolbar{
                region  { // Only needed if you want content on the left side
                    //hgrow = Priority.SOMETIMES
                }
                button("Test") {
                    action{
                    }
                }
                button("Test2") {
                    action{
    
                    }
                }
            }
            stackPane = stackpane {
                prefWidth = 600.0
                prefHeight =508.0
            }
            createCanvas()
        }
    
    
    
        fun createCanvas(){
            canvas = PannableCanvas().apply {
                children.add(topCell)
                stackPane.children.add(this)
                setTranslateX(0.0)
                setTranslateY(0.0)
            }
    
            val sceneGestures = SceneGestures(canvas)
            stackPane.addEventFilter(MouseEvent.MOUSE_PRESSED, sceneGestures.onMousePressedEventHandler)
            stackPane.addEventFilter(MouseEvent.MOUSE_DRAGGED, sceneGestures.onMouseDraggedEventHandler)
            stackPane.addEventFilter(ScrollEvent.ANY, sceneGestures.onScrollEventHandler)
    
            canvas.addGrid()
        }
    }
    `
    
    `class PannableCanvas : Pane() {
        var myScale: DoubleProperty = SimpleDoubleProperty(1.0)
        init {
            prefWidth = 600.0
            prefHeight = 500.0
            // add scale transform
            scaleXProperty().bind(myScale)
            scaleYProperty().bind(myScale)
        }
        /**
         * Add a grid to the canvas, send it to back
         */
        fun addGrid() {
            val w = 600.0 //boundsInLocal.width
            val h = 500.0 //boundsInLocal.height
    
            // add grid
            val grid = Canvas(w, h)
    
            // don't catch mouse events
            grid.isMouseTransparent = true
            val gc = grid.graphicsContext2D
            gc.stroke = Color.GRAY
            gc.lineWidth = 1.0
    
            // draw grid lines
            val offset = 50.0
            var i = offset
            while (i < w) {
                gc.strokeLine(i, 0.0, i, h)
                gc.strokeLine(0.0, i, w, i)
                i += offset
            }
            children.add(grid)
            grid.toBack()
        }
    
        var scale: Double
            get() = myScale.get()
            set(scale) {
                myScale.set(scale)
            }
    
        fun setPivot(x: Double, y: Double) {
            translateX = translateX - x
            translateY = translateY - y
        }
    }`
    
    `class DragContext {
        var mouseAnchorX = 0.0
        var mouseAnchorY = 0.0
        var translateAnchorX = 0.0
        var translateAnchorY = 0.0
    }
    
    
    /**
     * Listeners for making the scene's canvas draggable and zoomable
     */
    class SceneGestures(var canvas: PannableCanvas) {
        private val sceneDragContext = DragContext()
        val onMousePressedEventHandler = EventHandler<MouseEvent> { event -> // right mouse button => panning
                if (!event.isSecondaryButtonDown) return@EventHandler
                sceneDragContext.mouseAnchorX = event.sceneX
                sceneDragContext.mouseAnchorY = event.sceneY
                sceneDragContext.translateAnchorX = canvas.translateX
                sceneDragContext.translateAnchorY = canvas.translateY
            }
        val onMouseDraggedEventHandler = EventHandler<MouseEvent> { event -> // right mouse button => panning
                if (!event.isSecondaryButtonDown) return@EventHandler
                canvas.translateX = sceneDragContext.translateAnchorX + event.sceneX - sceneDragContext.mouseAnchorX
                canvas.translateY = sceneDragContext.translateAnchorY + event.sceneY - sceneDragContext.mouseAnchorY
                event.consume()
            }
    
        /**
         * Mouse wheel handler: zoom to pivot point
         */
        val onScrollEventHandler = EventHandler<ScrollEvent> { event ->
                val delta = 1.1
                //var scale: Double = canvas.getScale() // currently we only use Y, same value is used for X
                var scale: Double = canvas.scale // currently we only use Y, same value is used for X
                val oldScale = scale
                if (event.deltaY < 0) scale /= delta else scale *= delta
                scale = clamp(scale, MIN_SCALE, MAX_SCALE)
                val f = scale / oldScale - 1
                val dx = event.sceneX - (canvas.boundsInParent.width / 2 + canvas.boundsInParent.minX)
                val dy = event.sceneY - (canvas.boundsInParent.height / 2 + canvas.boundsInParent.minY)
                //canvas.setScale(scale)
                canvas.scale = scale
    
                // note: pivot value must be untransformed, i. e. without scaling
                canvas.setPivot(f * dx, f * dy)
                event.consume()
            }
    
        companion object {
            private const val MAX_SCALE = 10.0
            private const val MIN_SCALE = .1
            fun clamp(value: Double, min: Double, max: Double): Double {
                if (java.lang.Double.compare(value, min) < 0) return min
                return if (java.lang.Double.compare(value, max) > 0) max else value
            }
        }
    }`
    opened by Harrisonust 0
  • Set window icons for Alerts

    Set window icons for Alerts

    Setting icons in the JavaFX way, they won't be set. So the following expression isn't effective when using TornadoFX: (alert.dialogPane.scene.window as Stage).icons += (Image(getResStream("/desktop/images/dialog-warning.png")))

    Is there another way to achieve this? The "alert()" builder from TornadoFX seems to create the same Alert object as the Alert() constructor, so there are no functions like openModal() available, which would return a Stage in which icons could be added.

    opened by Hely0n 0
Releases(v1.7.20)
  • v1.7.20(Feb 5, 2020)

    Fixed

    • #991: App with NoPrimaryViewSpecified throws Exception in Application stop method
    • #1026 whenDockedOnce/whenUndockedOnce did not deregister correctly
    • #1115 Make InternalWindow aware of BorderPane parent (https://github.com/edvin/tornadofx/issues/1115)
    • #1134 Allow negative numbers in stripNonNumeric

    Changes

    • openInternalWindow() was made public (https://github.com/edvin/tornadofx/issues/989)
    • Scope.deregister() clears EventBus subscriptions associated with a particular scope
    • App.stop() clears all EventBus subscriptions

    Additions

    • subscene builder
    • The fxml() delegate now accepts an InputStream, for loading FXML from DB or resources.stream("/my/classpath/to.fxml") (https://github.com/edvin/tornadofx-guide/issues/107)
    • Generic HttpEntity support in HttpClientRequest (https://github.com/edvin/tornadofx/issues/996)
    • JsonConfig.AddEmptyStrings controls if empty strings are added to Json objects or treated as null
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.20.jar(3.61 MB)
  • v1.7.19(May 12, 2019)

    Another bugfix and small enhancement release!

    Fixed

    • SmartResize takes invisible columns into account (https://github.com/edvin/tornadofx/issues/889)
    • radiomenuitem didn't store value parameter properly (https://github.com/edvin/tornadofx/issues/737)
    • fitToWidth/fitToHeigh binds prefWidth/prefHeight instead of minWidth/minHeight properties (https://github.com/edvin/tornadofx/issues/886)
    • menu/item builders now observes FX.ignoreParentBuilder
    • Renamed labelProperty to textProperty in AbstractField
    • Wizard next button was enabled even when current page was not complete (https://github.com/edvin/tornadofx/issues/960)
    • App primary view would continue to receive onDock/onUndock after its app instance was stopped and out of scope (https://github.com/edvin/tornadofx/issues/973)

    Changes

    • Opened up HttpClientEngine and HttpURLEngine for easier subclassing/configuration of the Rest engine
    • Deprecated observableList() in favour of observableListOf(), and [List, Set, Map].observable() in favour of [List, Set, Map].asObservable() to be consistent with the Kotlin standard library.
    • Subdelegation of workspace button states (https://github.com/edvin/tornadofx/issues/894)
    • Kotlin 1.3.20
    • Moved all css helper extension functions from Node/Tab/Menu etc to Styleable (https://github.com/edvin/tornadofx/issues/944)

    Additions

    • FX.messagesNameProvider property to dynamically compute the name of the resource bundle of a given component class. (https://github.com/edvin/tornadofx/issues/872)
    • FX.fxmlLocator function to provide custom FXML locations globally
    • Added top level functions for creating (observableListOf(), etc) and converting (List<T>.asObservable(), etc) observable lists, sets and maps; and extension functions to work with them too (ObservableList<T>.shuffle(), etc).
    • Submenu support for MenuButton (https://stackoverflow.com/questions/54393983/how-to-make-a-submenu-within-a-menubutton-in-javafx)
    • Added cubiccurveTo builder (https://github.com/edvin/tornadofx/issues/911)
    • onLeftClick() and onRightClick()
    • Convenience function builders for SimpleXXXProperty classes (https://github.com/edvin/tornadofx/pull/935)
    • Added splitmenubutton builder
    • togglegroup() builder accepts property parameter (https://github.com/edvin/tornadofx/issues/956)
    • Added extensions and operators for vector math
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.19.jar(3.58 MB)
  • v1.7.18(Dec 28, 2018)

    Fixed

    • config no longer accepts null values, as the underlying Properties store won't allow them (https://github.com/edvin/tornadofx/issues/792). The set function that takes Pair still accepts null as the value, but will remove the key if the value is null.
    • the di() delegate no longer calls out to the DIContainer for every access, effectively caching the lookup (https://github.com/edvin/tornadofx/issues/837)
    • More efficient timer for delayed runLater calls (https://github.com/edvin/tornadofx/pull/836)
    • runAsyncWithProgress cannot target an UI element with no parent, will no throw Exception with warning (https://github.com/edvin/tornadofx/issues/873)

    Changes

    • App.scope is overridable
    • DefaultScope deprecated, use FX.defaultScope instead
    • The Workspace inside the scope of a UIComponents will assume the Workspace it is docked in (https://github.com/edvin/tornadofx/issues/806)
    • Kotlin 1.3.11
    • bindSelected for ViewModel gets out modifier (https://github.com/edvin/tornadofx/issues/823)
    • Spinner.required() validator (https://github.com/edvin/tornadofx/issues/871)

    Additions

    • TableView.onEditStart() and TableColumn.cancel() functions which can be used to intercept editing events
    • resources.media() to load a Media instance from resources
    • Media.play() shortcut which creates a MediaPlayer and plays the Media
    • Wipe and Dissolve view transitions
    • tab builder assigns UIComponent.icon as Tab graphic
    • ComboBox.bindSelected() (https://github.com/edvin/tornadofx/issues/829)
    • TextInputControl.requiredWhen()
    • colorpicker builder with property binding support
    • movable parameter for openInternalWindow() (https://github.com/edvin/tornadofx/issues/863)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.18.jar(2.72 MB)
  • v1.7.17(Aug 19, 2018)

    Fixed

    • OnDock Called Twice In openInternalWindow (https://github.com/edvin/tornadofx/issues/772)
    • TreeView.lazypopulate leafcheck logic was reversed (https://github.com/edvin/tornadofx/issues/773)
    • onCancel() is now called when reusing Wizard instance
    • Observable collection delegates removed because they shadow observable properties (See Properties.kt:L212)
    • The style property of ListCell will be cleared by the framework so it can be manipulated in cellFormat without side effects (https://stackoverflow.com/questions/51459371/custom-cell-format-listview-tornadofx-on-delete-item)
    • Escape closes window only works first time for Views (https://github.com/edvin/tornadofx/issues/764)
    • Reused modal didn't get stage icons set (https://github.com/edvin/tornadofx/issues/779)

    Changes

    • Kotlin 1.2.60
    • ViewModel binding dirty tracking for ListProperty (https://stackoverflow.com/questions/50364458/tornadofx-bind-dirty-properties-of-different-view-models)
    • Workspace.dock() will log a warning message if a child is docked while the workspace is not showing
    • SortedFilteredList.setAllPassThrough property controls if setAll should be forwarded to the underlying list (https://github.com/edvin/tornadofx/issues/344) and (https://github.com/edvin/tornadofx/issues/681)
    • EventBus deliveries will continue even after a subscriber throws exception
    • UIComponent callback onBeforeShow is called for all top level UIComponents
    • Primary View onDock is now called after the stage is shown. Now it aligns with the timing for secondary windows.
    • All asyncItems function parameters operate on FXTask
    • removeFromParent now supports TreeItem (https://github.com/edvin/tornadofx/issues/776)

    Additions

    • UIComponent.whenUndockedOnce() and whenDockedOnce callbacks
    • onTabSelected callback in UIComponent when connected to a TabPane
    • finally(callback) for runAsync and other task builders
    • Window.aboutToBeShown property avoid false positives for invisible Workspace warning (https://github.com/edvin/tornadofx/issues/755)
    • Slideshow slides supports optional timeout, which will advance to the next slide using the Slide transition
    • importStylesheet now supports file, http and https in addition to classpath resources (https://github.com/edvin/tornadofx/issues/762)
    • raduimenuiutem builders now accepts value property (https://github.com/edvin/tornadofx/issues/737)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.17.jar(2.68 MB)
  • v1.7.16(May 13, 2018)

    Fixed

    • runAsyncWithProgress must Unwrap ToolBar parent (https://github.com/edvin/tornadofx/issues/687)
    • Calling close() inside InternalWindow would also close the parent
    • placeholder for list type controls should not require list type parameter
    • Added warning log message when WorkspaceApp is called with a Workspace subclass as main view paramter
    • Fix bug caused by not properly removing nodes from ToolBar
    • Fixed issues generating CSS for dashed strokes in shapes and borders
    • contextmenu builder returns ContextMenu instance instead of EventTarget (https://github.com/edvin/tornadofx/issues/702)
    • togglebutton and radiobutton builders moved from Node to EventTarget (https://github.com/edvin/tornadofx/issues/716)
    • Workspace now undocks closed tabs correctly (https://github.com/edvin/tornadofx/issues/718)

    Changes

    • Kotlin 1.2.41
    • Workspace.navigateForward() made public
    • Added missing pseudoclasses to CSS DSL
    • HostServices is now retrieved from Application.getHostServices() instead of sun/internal API

    Additions

    • --dicontainer=diContainerClass parameter allows assignment of DIContainer from command line (https://github.com/edvin/tornadofx-idea-plugin/issues/56)
    • readonly and cancel pseudoclasses added to type safe CSS
    • Added add/remove/toggle class for Tab
    • ContextMenu.radiomenuitem (https://github.com/edvin/tornadofx/issues/646)
    • mutableList can now be bound to an ObservableMap
    • CssSelectionBlock now has all relation selectors (see CssSubRule.Relation)
    • TableView DND Reorder testapp
    • onCancel callback in Wizard (https://github.com/edvin/tornadofx/issues/712)
    • combobox.editableWhen() - also works for DatePicker since it extends ComboBoxBase (https://github.com/edvin/tornadofx/issues/717)
    • editableWhen() added for TableView, TreeTableView, ListView
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.16.jar(2.66 MB)
  • v1.7.15(Feb 18, 2018)

    Another good mix of fixes and features, plus another round of huge internal refactorings to improve code quality and consistency.

    Important note: The TableView column builder for readonly non-observable properties was renamed to readonlyColumn because it shadowed the (much more important) builder for observable properties. This is a breaking, but nessescary change. Apologies for not catching this as the new builder was implemented. Read more about it in https://github.com/edvin/tornadofx/issues/599

    Fixed

    • onEditCommit {} listens for changes in nested columns
    • UIComponent.close() should be able to close primary stage as well (https://github.com/edvin/tornadofx/issues/622)
    • SmartResize.Policy manual resize broken (https://github.com/edvin/tornadofx/issues/570)
    • TableView bound to ListProperty should rebind when value changes
    • Allow calling Workspace.disableNavigation() when workspace is empty
    • Thread pools are reinitialized on App.start() to support stop/start multiple times within the same JVM
    • ServiceLoader provided interceptors were added every time an App class was initialized
    • inheritParamHolder and inheritScopeHolder are cleared on Application stop (https://github.com/edvin/tornadofx/issues/602)
    • smartResize throws exception for hidden columns (https://github.com/edvin/tornadofx/issues/606)
    • The getters and setters of horizontalPadding and verticalPadding did not correspond

    Changes

    • Kotlin 1.2.21
    • Many internal refactorings
    • AnchorPaneConstraint properties now accept any Number, not just Double
    • AbstractField.textProperty was renamed to labelProperty to avoid confusion with the textProperty() exposed by textfields inside of a field
    • ItemViewModel.bind defaultValue parameter
    • Node builders inside of MenuItem will automatically assign the node to the graphic property of the menu item
    • The App class (main application entrypoint) no longer requires a primary view parameter, in case you want to show a tray icon or determinine what view to show some other way
    • Renamed tableview column builder for readonly non-observable properties to readonlyColumn (https://github.com/edvin/tornadofx/issues/599)
    • Renamed Node.index to Node.indexInParent to avoid subtle bugs (Partly fixes https://github.com/edvin/tornadofx/issues/598)
    • Removed CheckBoxCell in favor of inline cellFormat
    • ValidationContext.validate has a new parameter failFast, which can optimize the validation-process.
    • (Linked)HashMaps are generalized to (Mutable)Map
    • ArrayList are generalized to (Mutable)List

    Additions

    • StackPane.connectWorkspaceActions() along with StackPane.contentProperty and various Workspace related functions and properties (https://github.com/edvin/tornadofx/issues/604)
    • TextInputControl.filterInput allows you to discriminate what kind of input should be accepted for a text input control
    • String.isLong(), isInt(), isDouble() and isFloat()
    • checkmenuitem builder accepts string for keycombination and selected property
    • Node.index will tell you the Node's index in the parent container
    • placeholder builder for TableView, TreeTableView, ListView
    • obserableList() creates FXCollections.observableArrayList
    • ResourceBundle.format() provides a short way to insert translations with variables in them
    • ocpr is now available as extension function: attachTo
    • Insets.copy(), Intsets.horizontal, Intsets.vertical, Intsets.all
    • SortedFilteredList forwards setAll() to backing list
    • withEach/mapEach/mapEachTo are the receiver-functions of forEach/map/mapTo.
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.15.jar(2.64 MB)
  • v1.7.14(Dec 16, 2017)

    This release brings amongst other things, a fix to the long standing runAsync bug which could case the success and fail callbacks to not run if the work in runAsync completed (very) fast.

    Fixed

    • runAsync would skip the success/fail steps if no work was done in the op block
    • TableView Pojo Column references support boolean "is" style properties (https://github.com/edvin/tornadofx/issues/560)
    • TabPane.tab inside of an UIComponent is now scope aware
    • TreeView.lazyPopulate should never assign null list if filter results in no items

    Changes

    • Kotlin 1.2.10
    • Node builders inside of ButtonBase will automatically assign the node to the graphic property of the Button

    Additions

    • ConfigProperties (config) is now Closable so it can be used with use
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.14.jar(2.55 MB)
  • v1.7.13(Dec 8, 2017)

    Another bugfix and stability enhancement release as we're gearing up to Java 9 compatibility!

    Fixed

    • Navigation button issue when already docked view was docked again (https://github.com/edvin/tornadofx/issues/526)
    • Internal thread pools are shutdown on app exit. Running threads in the default thread pool will still block application stop.
    • ComboBox.makeAutoCompletable() inspects listView.prefWidth for being bound before attemting to set it (https://github.com/edvin/tornadofx/issues/530)
    • Wizard.canGoBack override caused NPE (https://github.com/edvin/tornadofx/issues/211)

    Changes

    • Kotlin 1.2.0
    • ItemViewModel.bindTo(itemFragment) supports all item fragments now, not just ListCellFragment
    • lambda's that return unit are no longer nullable. use the default-lambda instead
    • ChildInterceptor is now an Interface.
    • Component.messages are fetched using the classloader that defined the Component subclass (https://github.com/edvin/tornadofx/issues/553)

    Additions

    • cellFragment support for DataGrid
    • ObservableValue.isBlank() and ObservableValue.isNotBlank() which returns BooleanBinding. Useful for binding to TextField enabled/visible state
    • Added owner and title parameters to alert and other dialog builders (https://github.com/edvin/tornadofx/issues/522)
    • TextInputControl.editableWhen
    • multiSelect() for TreeView, TreeTableView, TableView and ListView
    • Stylesheets can now be added specificly to a Parent- Node with addStylesheet
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.13.jar(2.55 MB)
  • v1.7.12(Oct 30, 2017)

    This release contains an enormous amount of internal refactoring (not mentioned in the changelog) as well as some neat new features and bug fixes :)

    Fixed

    • Fixed #434 leaf nodes are now getting set as expected for lazypopulate.
    • Style builder can be applied to PopupControl, Tab, TableColumnBase (https://github.com/edvin/tornadofx/issues/476)
    • Better handling of Column.makeEditable() for properties that implement Property

    Changes

    • Refactoring: Moved all extension functions and properties targeting TreeView from Nodes.kt to TreeView.kt.
    • alert builder accepts optional owner parameter (https://github.com/edvin/tornadofx/issues/483)

    Additions

    • fitToParentHeight/Width/Size as well as fitToHeight/Width/Size(region) helpers (https://github.com/edvin/tornadofx/pull/519)
    • beforeShutdown allows you to register shutdown hooks
    • DataGridPaginator component to help with pagination for DataGrid
    • runAsync supports daemon parameter to control thread characteristics (https://github.com/edvin/tornadofx/pull/508)
    • Node.runAsyncWithOverlay
    • Latch, a subclass of CountdownLatch that exposes a lockedProperty and provides immediate release ability
    • Inline type safe stylesheet on Parent using the stylesheet builder
    • Tab.close()
    • JsonBuilder.add() supports Iterable (Turned into JsonArray)
    • Added customitem menu item builder (https://github.com/edvin/tornadofx/pull/488)
    • The default lefCheck for lazypopulate is now also recognizing an empty list as a leaf.
    • menubutton builder (https://github.com/edvin/tornadofx/issues/461)
    • MenuButton.item builder
    • Added Fragment support forTreeCell
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.12.jar(2.29 MB)
  • v1.7.11(Sep 17, 2017)

    Fixed

    • Accessing last item in DataGridFocusModel was not possible
    • Severe performance bug in SmartResize policy causing it to add exessive number of listeners (https://github.com/edvin/tornadofx/issues/460)

    Changes

    • Parameters passed to Views will now be updated if you do another find() (https://github.com/edvin/tornadofx/issues/443)
    • SingleAssign now throws UninitializedPropertyAccessException instead of Exception
    • Removed inc() and dec() from properties
    • rangeTo from properties is now lazy
    • loadFont size parameter is changed from Double to Number
    • Lots of internal refactoring thanks to @tieskedh
    • Kotlin 1.1.4
    • Wizard and ViewModel are now internationalized
    • imageview() builder accepts ObservableValue<Image?> (https://github.com/edvin/tornadofx-guide/issues/43)
    • added option to increment and decrement spinners by scrolling (https://github.com/edvin/tornadofx/pull/425)
    • onUndock is now called for the View currently embedded as the scene root of a Window when it closes (https://github.com/edvin/tornadofx/issues/427)
    • Launch helper for nicer main functions (https://github.com/edvin/tornadofx/pull/431)

    Additions

    • TreeTableView.bindSelected()
    • CheckMenuItem.bind()
    • Button builders with text property support
    • Collection Property Delegates (https://github.com/edvin/tornadofx/pull/454)
    • Workspace.create button and corresponding UIComponent onCreate callback and creatable property
    • Lots of reified functions
    • The default ErrorHandler shows structured information about failed HTTP requests
    • RestException containing request, response and the underlying exception
    • Added JsonBuilder.add(key, Iterable) to avoid having to call toJSON() on it (https://github.com/edvin/tornadofx/issues/414)
    • ViewModel partial rollback (https://github.com/edvin/tornadofx/issues/420)
    • FX.addChildInterceptor that can veto or custom add builder children to their parent. Useful for MigPane for example.
    • Tab.select() for easier selection of tab without having to access tabPane.selectionModel
    • TabPane.contains(UIComponent) and Iterable.contains(UIComponent)
    • Override -fx-accent with type-safe CSS property accentColor
    • Component.paramsProperty can be used to detec changes to incoming parameters (overriden on new find)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.11.jar(2.20 MB)
  • v1.7.10(Aug 13, 2017)

    This is a bug fix release to address a few regressions introduced in 1.7.9.

    Fixed

    • Fieldset captions are gone (https://github.com/edvin/tornadofx/issues/399)
    • Fieldset padding is missing (https://github.com/edvin/tornadofx/issues/401)
    • AutoCompleteComboBoxSkin no longer throws upon reconfiguration

    Changes

    • AutoCompleteComboBoxSkin: Added an option to use automatic width for the popup
    Source code(tar.gz)
    Source code(zip)
  • v1.7.9(Aug 4, 2017)

    Additions

    • weak delegate for easier construction of weak references that need a deinit callback
    • The following extension functions (managedWhen, visibleWhen, hiddenWhen, disableWhen, enableWhen, removeWhen, onHover) now return the node the are called on.
    • TableColumn.cellFragment to match ListView.cellFragment + SmartTableCell which encapsulate cellFormat, cellCache and cellFragment
    • bindChildren(observableSet, converter) to complement the observableList version
    • sequentialTransition, parallelTransition builders (https://github.com/edvin/tornadofx/issues/373)
    • ObservableList<*>.sizeProperty keeps track of the number of items in an ObservableList
    • KeyboardLayout which can export to keyboard-layout-editor.com format
    • ObservableValue.onChangeOnce() and ObservableValue.onChangeTimes(n) will disconnect listener after n events
    • ViewModel.markDirty(property) to explicitly set a property dirty, for example when a bound list is changed internally
    • ViewModel supports binding maps
    • MutableMap.toProperty(key) { generateProperty() } writes back into the map on change

    Fixed

    • Form and Field properties got updated to the new more concise syntax propertyName() vs. property
    • LazyTreeItem will now only set children once after getChildren is called.
    • DataGrid properly updates when operating on a bound list (https://github.com/edvin/tornadofx/issues/385)
    • DataGrid reselects same index if item at selected index is removed (https://github.com/edvin/tornadofx/issues/386)
    • imageview builder now accepts null from an ObservableValue<String>
    • TreeView.cellFormat now unbinds the textProperty and the graphicProperty
    • Reified type parameter to ViewModel.bind() to solve properties that are null at the binding call (https://github.com/edvin/tornadofx/issues/365)
    • ViewModel.bind() for properties that are null at the binding call + now supports Long amd ObservableList as well
    • Fixed Chart.series() bug (https://github.com/edvin/tornadofx/issues/354)
    • External/synced changes to bound ViewModel properties should not affect dirty state (https://github.com/edvin/tornadofx/issues/358)
    • showModal/showWindow now resizes the window before calling onDock, so the View can override placement easier (https://github.com/edvin/tornadofx/issues/360)
    • Avoid extension function confusion on Configurable by introducing a new ConfigProperties subclass and changing extension functions to member functions (https://github.com/edvin/tornadofx/issues/362)
    • TreeTableView.resizeColumnsToFitContent() now waits until the skin is available instead of naively deferring to the next pulse
    • Nested tableColumns with valueProvider lambda now nest correctly

    Changes

    • Kotlin 1.1.3-2
    • DataGrid receives focus on click
    • TableView refactoring, all cell manipulation functions are encapsulated in a SmartTableCell
    • ItemViewModel's bind methods accept properties that return nullable values (https://github.com/edvin/tornadofx/issues/389)
    • ViewModel binding mechanism has been rewritten and supports lists much better now
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.9.jar(2.12 MB)
  • v1.7.8(Jun 25, 2017)

    Additions

    • Stage.uiComponent()
    • ViewModel.clearDecorators()
    • Extensions for StringProperty and BooleanProperty

    Fixed

    • Improved ProgressIndicator size for runAsyncWithProgress

    Changes

    • Kotlin 1.1.3
    • openModal and openWindow returns the Stage
    • dialog builder operates on a StageAwareFieldset so it can close the dialog easier by calling close()
    • All JSON extractor functions support vararg keys, will pick the first available (https://github.com/edvin/tornadofx/issues/350)
    • ValidationContext.validate(decorateErrors = false) clears decorators
    • Property.plus(), minus(), etc now return Bindings instead of Properties
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.8.jar(2.06 MB)
  • v1.7.7(Jun 15, 2017)

    Oups! I broke the TableColumn.cellFormat function for some situations, so here is a bugfix release to replace 1.7.6. As a as a consolation you'll get a heap of extension functions to NumberProperty classes thanks to This PR from @TheJhonny007 :)

    This release also fixes a bug with extracting json properties from app.config.

    Additions

    • Extension functions to NumberProperty classes (obsNumOne + obsNumTwo etc)

    Fixed

    • Reverted cellFormat change from 1.7.6 (https://github.com/edvin/tornadofx/issues/349)
    • Accessing json properties from app.config inside a view looked up view.config instead of app.config (https://github.com/edvin/tornadofx/issues/346)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.7.jar(2.02 MB)
  • v1.7.6(Jun 13, 2017)

    It's that time of month again :) TornadoFX 1.7.6 brings many small improvements and bug fixes in addition to Digest Authentication support for the REST Client.

    The feature set is pretty complete by now, so we will turn our attention to even better plugin support and general improvements. Feature requests are still very much welcome of course!

    Additions

    • UIComponent.forwardWorkspaceActions(target) will override the current receiver of button states and action callbacks
    • replaceWith(component: KClass) accepts sizeToScene and centerOnScreen
    • titledpane builder that accepts the title as ObservableValue
    • TaskStatus.completed and FXTask.completedProperty can be used to listen to changes in completion state of a task
    • runLater with optional delay: runLater { } and runLater(10.seconds) { .. }
    • ObservableValue.awaitUntil waits on the UI thread without blocking until a given value is set before resuming execution
    • ViewModel.bind can create observable properties from mutable vars: val name = bind(MyObject::name)
    • Rest.Response.Status enum with all official http status codes. (https://github.com/edvin/tornadofx/issues/330)
    • hbox and vbox builders now have optional alignment parameter
    • Workspace.dockOnSelect Will automatically dock the given UIComponent if the ListMenuItem is selected.
    • Rest client supports Digest Authentication
    • Inline commands can be defined with command { } builder pattern
    • hyperlink builder has optional graphic parameter
    • UIComponent has currentStage, setWindowMinSize(width, height) and setWindowMaxSize(width, height)
    • DrawerItem has expandedProperty and expanded var (https://github.com/edvin/tornadofx/issues/332)
    • UIComponent.replaceWith has centerOnScreen parameter
    • Shortcut overload for Commands: shortcut(shortcut, command, param)

    Fixed

    • TableColumn.useTextField() accepts Property<> - no longer requires ObjectProperty<>
    • Workspace navigation now behaves more like a browser with regards to back/forward button functionality
    • ConcurrentModificationException in EventBus fire mechanism
    • UIComponent.headingProperty is bound to titleProperty by default, will be unbound if assigned value
    • DefaultErrorHandler correctly handles errors with no stacktrace available (https://github.com/edvin/tornadofx/issues/328)
    • Non-bound properties inside ViewModels can locate it's ValidationContext, and hence can now be used with validators
    • SortedFilteredList will not overwrite the backing list when column sorting is enabled in TableView (setAll disabled) (https://github.com/edvin/tornadofx/issues/344)
    • RowExpanders containing nested TableViews no longer inherits white label text when owning row is selected
    • Calling cellFormat on a TableCell that already has a formatter will now add the new formatter as a decorator instead of overwriting the old
    • cellDecorator only decorates cells with items. It previously ran also when a cell item became null

    Changes

    • Kotlin 1.1.2-5
    • Workspace will preemptively register for current scope in init()
    • runAsyncWithProgress will display the progress indicator in the graphic property if the parent is Labeled
    • Cleaned up menu and item builders, might require parameter adjustment in some cases
    • UIComponent.currentWindow is fetched from root.scene.stage, falls back to modalStage or primaryStage
    • ListMenu.activeItem accepts null to signal that no menu item is active
    • Removed children parameter from hbox and vbox builders - they were early remnants from before we realized how powerful builders could be :)
    • action delegate no longer has ActionEvent as parameter so it can be used for no-args function references. Fallback to setOnAction if you need the event.
    • Injectable was a misnomer and has been deprectated in favor of ScopedInstance
    • TaskStatus no longer disconnects the current task when the task is completed
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.6.jar(2.02 MB)
  • v1.7.5(May 19, 2017)

    Important notice: The field builder used to operate on the inputContainer inside the Field. This has been changed so that it now operates on the field itself. If you did something like parent.isVisible = false to hide the field, you must now change your code to isVisible = false. This new behavior is more as one would expect and hopefully the change won't cause any trouble to anyone.

    Additions

    • ListMenu.item builder gets tag parameter (can be used to identify the item)
    • EventTarget.tag and tagProperty, useful for identifying Tabs, ListMenuItem and other components used in "selected" situations.
    • Map.queryString creates an URL encoded query string from a Map. Useful for REST calls.
    • Tab.enableWhen/disableWhen/visibleWhen
    • TabPane.tab builder takes optional tag parameter. If no text parameter is supplied, tag.toString() is used
    • Node.cache will create and cache a node inside another node. Useful for Cell implementations to reduce memory footprint. graphic = cache { createNode() }
    • Rest client supports PATCH (https://github.com/edvin/tornadofx/issues/320)
    • warning(), error(), confirmation() and information() shortcuts to alert()
    • Command bindings accepts optional parameter using invoke: button { command = someCommand(someParam) } or button { command = someCommand with someParam }
    • ChoiceBox now supports Commanding
    • TextField now supports Commanding
    • TreeTableSmartResize.POLICY - activate with smartResize() (https://github.com/edvin/tornadofx/issues/316)
    • removeWhen/visibleWhen/enableWhen/disableWhen etc functions now also take an observable instead of a function that returns an observable.
    • The label builder is now capable of taking a graphic node label("some text", graphic)
    • ComboBoxBase.required() validator
    • SmartResize.POLICY can now be installed by calling smartResize() on any TableView
    • SmartResize will automatically resize if the itemsProperty of the TableView changes value
    • Workspace.showHeadingLabelProperty controls whether the heading is shown in the Workspace toolbar or not
    • TableView/TreeTableView requestResize() will reapply SmartResize policy, useful after content change
    • Column.makeEditable() works for all number subclasses
    • Workspace navigateForward and navigateBack explicit functions
    • Style builder for MenuItem (https://github.com/edvin/tornadofx/issues/327)
    • imageview builder overloads that accepts observable urls or images

    Fixed

    • AutoJsonModel supports String types
    • HTTPUrlConnection based Rest Client Engine will read data from response even when not successful
    • Support view reloading in OSGi environment
    • Live Views did not reload changed classes correctly
    • Fixed equals/hashCode in FXEventRegistration, could cause events to not fire on similar components
    • lazyPopulate child factory was called on UI thread (https://github.com/edvin/tornadofx/issues/318)
    • SmartResize.requestResize() some times resulted in misaligned column headers
    • JsonModelAuto supports more types and doesn't produce duplicates (before: name and nameProperty - now: just name)
    • SmartResize flickers (https://github.com/edvin/tornadofx/issues/321)
    • Workspace navigation (viewPos index) stays intact even when views are manually removed from the viewStack
    • ObservableValue.select() notice changes to outer property (https://github.com/edvin/tornadofx/issues/326)
    • Ignore duplicate onUndock call when both parent and scene are set to null

    Changes

    • Removed Workspace experimental warning
    • alert content parameter is now optional
    • commandProperty and commandParameterProperty are now writable so you can choose between bind or assign
    • CSS warning should not be issued in OSGi environment, since bundle activator installs CSS URL Handler
    • All shape builders accepts Number instead of Double so you can write circle(10, 10, 5) instead of circle(10.0, 10.0, 5.0)
    • ComboBox.validator moved to ComboBoxBase.validator to support ColorPicker and DatePicker as well
    • Removed InstanceScoped and removed it from Wizard. It was not needed.
    • Deprecated menuitem builders in favor of item builders, which work the same way as other builders with respect to action (IDEA provides quick fix)
    • TreeView.lazyPopulate() is now data driven. If the returned list is observable, changes will be reflected in the tree (https://github.com/edvin/tornadofx/issues/317)
    • field builder now operates on the field itself instead of the inputContainer. You can now hide() the field directly in the function reference.
    • TableColumn.useProgressBar() supports Number subtypes instead of only Double
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.5.jar(1.97 MB)
  • v1.7.4(Apr 28, 2017)

    Additions

    • wrapper builder which builds a node around the existing View root
    • ListMenu control and corresponding listmenu builders
    • validator function takes optional model parameter for use with properties not currently registered with the ViewModel (FXML support)
    • ToggleGroup.selectedValueProperty() is a writable property of any type you choose. Set togglebutton(value) or radiobutton(value) to configure the value represented by each toggle.
    • Wizard.enterProgresses = true will go to next page when complete and finish on last page (https://github.com/edvin/tornadofx/issues/310)
    • ViewModel.onCommit(commits: List<Commit>) callback with more information about the commit
    • imageview builder that takes an image in addition to the existing one that takes a url
    • fxml delegate supports setting optional root element
    • Improved Java interop
    • Java version of FX.find() can be called without specifying scope

    Fixed

    • Java version of Component.find() defaults to current component scope instead of DefaultScope
    • NPE in layout debugger (https://github.com/edvin/tornadofx/issues/305)

    Changes

    • Kotlin 1.1.2
    • findParentOfType accepts subclasses
    • splitpane() now has an optional orientation parameter
    • Clicking outside of a modal InternalWindow click now play an error sound to indicate modality (https://github.com/edvin/tornadofx/issues/308)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.4.jar(1.91 MB)
  • v1.7.3(Apr 19, 2017)

    Hot on the heels of the 1.7.2 release, this is mainly a bugfix release but it also provides better Android and vanilla Java compatibility.

    Additions

    • ScrollPane.edgeToEdge boolean var to control the "edge-to-edge" style class (https://github.com/edvin/tornadofx/issues/302)
    • Android SDK compatibilty (See https://github.com/edvin/tornadofx-android-compat)
    • Added baseColor CSS property
    • lazyContextmenu to add context menus that instantiate when the menu actually opens.

    Changes

    • Improved Java interop
    • Removed faulty choicebox builder and replaced it with one similar to the combobox builder
    • authInterceptor was deprecated in favor of better named requestInterceptor

    Fixes

    • Fixed ViewModel validation bug for ComboBox, ChoiceBox and Spinner
    • Autocomplete ComboBox listview matches width of ComboBox by default
    • JsonStructure.save(path) actually saves (https://github.com/edvin/tornadofx/pull/300)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.3.jar(1.86 MB)
  • v1.7.2(Apr 14, 2017)

    TornadoFX 1.7.2

    This release features a shiny new Wizard API, improved Form layout, data driven TreeView, ViewModel partial commit/validate, shortpress/longpress touch support as well as other features, improvements and bug fixes.

    • shortpress/longpress actions (https://github.com/edvin/tornadofx/pull/286)
    • Form layout supports arbitrary layout containers inside fieldsets (to support multiple rows of fields or any other form layout)
    • radiomenuitem builder default argument for keyCombination (https://github.com/edvin/tornadofx/issues/298)
    • ViewModel bindings configured with autocommit must pass validation before the value is committed
    • find takes op block to let you operate on the found Component directly
    • Node.toggleButton behaves correctly if no togglegroup is available (https://github.com/edvin/tornadofx/issues/296)
    • ViewModel partial commit and validate: commit(field1, field2)
    • Wizard component
    • ViewModel.valid property will be updated as validators are added
    • UIComponent.closeable property and corresponding default configuration in Workspace.defaultCloseable
    • TabPane.add(SomeView::class) will bind towards title and closeable state of the UIComponent (https://github.com/edvin/tornadofx/issues/294)
    • TreeView.populate() is now data driven. If the returned list is observable, changes will be reflected in the tree
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.2.jar(1.86 MB)
  • v1.7.1(Apr 6, 2017)

    Important version note

    TornadoFX is now built against Kotlin 1.1.1 and compiled with jvmTarget 1.8, which means that your code must do the same. Update your build system to configure the jvmTarget accordingly.

    For Maven, you add the following configuration block to kotlin-maven-plugin:

    <configuration>
        <jvmTarget>1.8</jvmTarget>
    </configuration>
    

    For Gradle, it means configuring the kotlinOptions of the Kotlin compilation task:

    compileKotlin {
        kotlinOptions.jvmTarget= "1.8"
    }
    

    Failing to do so will yield errors about the compiler not being able to inline certain calls.

    See Kotlin docs for Gradle and Maven.

    Changes

    • Node.findParentOfType will now also find UIComponents
    • Configurable default states for savable, refreshable and deletable (Workspace.defaultXXX property)
    • Workspace.delete button and onDelete, deletableWhen and onDelete on UIComponent
    • TabPane.connectWorkspaceActions makes the TabPane a target for save/refresh/delete actions
    • Autocomplete tooltip mode for non editable ComboBox (https://github.com/edvin/tornadofx/pull/293)
    • UIComponent.app points to the current application instance
    • config base path configurable via App.configBasePath
    • Per component config path configurable via UIComponent.configPath
    • Global configuration object app.config works like the one in UIComponent, saves to conf/app.properties by default
    • TabPane.contentUiComponent will retrieve the UIComponent embedded in the selected tab
    • UIComponent callbacks for onNavigateBack and onNavigateForward can veto Workspace navigation
    • Improved TableView.selectOnDrag (https://github.com/edvin/tornadofx/issues/262)
    • Functions to load and save Json objects and JsonModel
    • Rest Client supports absolute URI's without appending base URI (https://github.com/edvin/tornadofx/issues/289)
    • replaceWith gets sizeToScene boolean parameter, defaults to false (https://github.com/edvin/tornadofx/issues/283)
    • shortcut("keyCombo") { .. } and shortcut(KeyCombo) { .. } configures key press initiated actions
    • UIComponent.accelerators map now works from any View, not just Views embedded in a Workspace (https://github.com/edvin/tornadofx/issues/253)
    • Added Scope.hasActiveWorkspace to check if the workspace inside the current scope has been activated
    • Button.shortcut also works when button is embedded in sub view (https://github.com/edvin/tornadofx/issues/253)
    • DataGrid correctly calculates horizontal scrollbar
    • DataGrid.maxRows will constrain the max number of rows and override maxCellsInRow if needed (https://github.com/edvin/tornadofx/issues/287)
    • DataGrid properties are now StylableObjectProperties to make them bindable
    • config can now read and write JsonObject and JsonArray
    • TableView.bindSelected uses listener instead of unidirectional binding
    • Simplified ItemViewModel binding: val name = bind(Customer::nameProperty) instead of the old val name = bind { item?.nameProperty }
    • Any?.toProperty() will wrap any value in an observable property, even nullable properties
    • TableColumnBase.style builder
    • Node.managedWhen builder binding
    • Int/Double Spinner builders merged into one Number builder for better compatibility
    • Spinner builders have defaults for min (0), max(100), initialValue (property.value if supplied) (https://github.com/edvin/tornadofx/issues/274)
    • paddingLeft/paddingRight converted from Double to Number
    • JsonObject.contains(text) and JsonModel.contains(text)
    • Button.action() shortcut istead of Button.setOnAction()
    • ObservableList.invalidate()
    • Dialog.toFront()
    • Node.whenVisible
    • ListCellFragment.onEdit
    • ItemViewModel allows passing in the itemProperty
    • First togglebutton builder inside a togglegroup will be selected by default (disable with selectFirst = false)
    • ToggleButton.whenSelected
    • SortedFilteredList refilters when items change (add, remove, permutate)
    • SortedFilteredList is editable and supports all functions of the ObservableList interface
    • ObservableXXXValue.onChange functions should support nullable values
    • Changed semantics of Node.removeWhen to switch visible/managed state instead of adding/removing from parent
    • Internal: ViewModel maintains a map between bound properties towards the ViewModel to support validators in a cleaner way without reflection calls to private APIs (https://github.com/edvin/tornadofx/issues/276)
    • Kotlin 1.1.1 and JvmTarget 1.8
    • SortedFilteredList.refilter() causes the existing predicate to be reevaluated
    • openModal(resizable) and openWindow(resizable) optional parameter
    • TextInputControl.trimWhitespace() enforces on focus lost instead of onChange (prevented adding words with whitespace)
    • ViewModel.bind accepts cast to IntegerProperty/DoubleProperty/FloatProperty/BooleanProperty even when binding is null at construction time
    • Added loadFont helper function
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Mar 4, 2017)

    Important version note

    TornadoFX Version 1.7.0 requires Kotlin 1.1. Make sure you update your IDE plugins to minimum:

    • Kotlin Plugin: 1.1.0-release
    • TornadoFX Plugin: 1.6.2.2

    After updating IntelliJ IDEA, make sure your Kotlin target version is 1.1 (Project Settings -> Modules -> Kotlin -> Language Version / API Version)

    You also need a full rebuild of your code. If you run into trouble, try to clean caches and restart IDEA (File -> Invalidate caches / Restart).

    Changes in this version

    • EventTarget.bindComponents(sourceList, converter) syncs the child nodes of the event target to the given observable list of UIComponents via the converter
    • EventTarget.bindChildren(sourceList, converter) syncs the child nodes of the event target to the given observable list via the converter
    • ObservableList.bind(sourceList, converter) syncs two lists and converts from one type to another on the fly
    • API Break: Removed Node.margin helper because it shadowed margin property on Nodes which had their own margin property
    • ValidationContext.validate() has optional decorateErrors parameter
    • ValidationContext and ViewModel has valid observable boolean value
    • Kotlin 1.1 dependency
    • Added MenuItem.visibleWhen
    • Fixed: workspace.dockInNewScope(params) operates on current scope instead of the new
    • buttonbar builder in form now creates and operates on a ButtonBar
    • contextmenu builder now works on any Node, not just Control
    • EventBus subscribe(times = n) parameter will unregister listener after it has fired n times (http://stackoverflow.com/questions/42465786/how-to-unsubscribe-events-in-tornadofx)
    • TextInputControl trimWhitespace(), stripWhitespace(), stripNonNumeric(), stripNonInteger continually strips or trims whitespace in inputs
    • JSON datetime function has optional millis parameter to convert to/from milliseconds since epoch instead of seconds
    • JsonConfig.DefaultDateTimeMillis = true will cause datetime to convert to/from milliseconds since epoch by default
    • Improved Form prefWidth calculations
    • MenuItem.enableWhen function
    • Custom tab support for Views. Views can be docked in tabs and even delegate to refreshable and savable for the surrounding View
    • resources stream/url/get helpers are not non-nullable
    • Added resources helper to App class
    • Added TrayIcon support (https://gitallhub.com/edvin/tornadofx/issues/255)
    • EventBus fire() function is now available from the App class
    • ComboBox.makeAutocompletable()
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.7.0.jar(1.67 MB)
  • v1.6.2(Feb 19, 2017)

    • resizeColumnsToFitContent takes nested columns into account
    • SmartResize.POLICY takes nested columns into account
    • scrollpane builder now has fitToWidth and fitToHeight params
    • typesafe pojo column builders for TableView and TreeTableView eg. column( "Name", MyPojo::getName )
    • spinner builders takes property param
    • include(fxmlFile) builder support
    • fxml() Views now supports nested includes / controllers injected via fxid() (name of controller is fx:id + "Controler")
    • SqueezeBox.fillHeight property
    • Added svgicon builder
    • Removed Node.alignment helper, it was misleading
    • Added collapsible parameter to titledpane builder
    • Added Component.hostServices property to access a JavaFX HostServices instance
    • Improved TableView.column builder so it finds mutable properties even when constructor params with same name is present (https://github.com/edvin/tornadofx/issues/247)
    • Workspace.viewStack is public
    • Workspace detects dynamic components anywhere inside the WorkspaceArea
    • TableView.selectOnDrag() will select rows or columns depending on the current selection mode
    • resources.text, resources.image and resources.imageview helpers
    • Workspace has NavigationMode Stack (default) and Tabs
    • closeModal() deprecated in favor of close() since it will also close tabs and non-modal + internal windows
    • SqueezeBox has multiselect option (still defaults to true)
    • ContextMenu.checkboxmenuitem builder
    • UIComponent.icon property used by Workspace and Drawer
    • Workspace Drawer support (workspace.leftDrawer/rightDrawer)
    • Drawer component
    • SqueezeBox panes are now closeable
    • Form buttonbar alignment is now working correctly
    • UIComponent.currentWindow property
    • openModal/openWindow defaults to currentWindow as owner (https://github.com/edvin/tornadofx/issues/246)
    • Accordion.fold has expanded parameter
    • Fixed: ComboBox with cellFormat does not show bound element (https://github.com/edvin/tornadofx/issues/245)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.6.2.jar(1.63 MB)
  • v1.6.1(Jan 26, 2017)

    • whenSaved and whenRefreshed lambdas as alternative to overriding onSave and onRefresh
    • Workspace onSave and onDock delegates to the docked View
    • InputStream.toJSON and .toJSONArray + resources.json(key) and resources.jsonArray(key)
    • Color.derive and Color.ladder
    • Rest.Response implements Closeable so it can be useed (https://github.com/edvin/tornadofx/issues/237)
    • UIComponent disableSave() and disableRefresh()
    • can now bind to a pojo by providing only a single getter ( eg. person.observable( JavaPerson::getId ) )
      • API break: previously returned a PojoProperty - now returns an ObjectProperty
      • uses javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder and will now propogate PropertyChangeEvents from the pojo
    • UIComponent.headingProperty is ObservableValue for easier binding
    • field builder supports orientation parameter which will cause input container to be a VBox instead of an HBox (https://github.com/edvin/tornadofx/issues/190)
    • UIComponents can now be instantiated manually instead of via inject() and find()
    • Input Control builders now support ObservableValue instead of just Property for automatic binding
    • ListView.useCheckbox()
    • ItemViewModel.asyncItem helper to reload the underlying item
    • Corrected Workspace.dockInNewScope, docking was performed in the old scope (!)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.6.1.jar(1.56 MB)
  • v1.6.0(Jan 18, 2017)

    This is the most feature packed release we have ever done! It includes some major features like Workspaces, TableView EditModel and a large number of fixes and improvements.

    We also made an API break, hence the 1.6.0 version number: View params are now map(property-ref, value) instead of vararg Pair(String, value) This is a pretty new feature that probably hasn't seen wide spread usage, so we found it best to clean up the API now.

    We added a new MenuItem builder called item which works like the other builders - the op block operates on the MenuItem, so you can call setOnAction to specify the action. This is in contrast to the old builder called menuitem where the op block represents the action. The new item builder allows the menu text to bound to an observable string and introduces an easier way to dynamically disable the item via disableWhen callback.

    Here is the full list of changes. Please allow us some time to update the guide with all these new goodies :)

    • Workspaces (https://edvin.gitbooks.io/tornadofx-guide/content/16.%20Workspaces.html)
    • OpenXXX functions: Windows opens centered over owner if owner is passed in as parameter (https://github.com/edvin/tornadofx/issues/231)
    • API break: View params are now map(property-ref, value) instead of vararg Pair(String, value)
    • menu builder correctly supports sub-menus
    • Introduced item menu item builder, should be used in favor of menuitem, which took the onAction callback insteadof an operation on the MenuItem as the op block parameter (breaks with the other builders)
    • menu builder accepts graphic parameter
    • ViewModel autocommit bindings doesn't affect dirty state any more
    • buttonbar builder for forms
    • ItemViewModel constructor takes optional initial value
    • ObservableList.asyncItems and ListProperty.asyncItems
    • confirm() function that executes an action if the user confirms
    • di delegate overload to support injecting a dependency by name (in addition to type)
    • builderFragment and builderWindow builders - fragment and window by just supplying a title and builder
    • ObservableList<T>.onChange to easy listening to change events from observable lists
    • setInScope() now uses correct KClass when entering the injectable into the components map
    • ItemViewModel.isEmpty boolean, complements empty property
    • setStageIcon(icon) will replace all existing icons with the supplied (https://github.com/edvin/tornadofx/issues/228)
    • TableColumn.useCheckbox(editable = true) now fires edit/commit events when value is changed
    • Create nested, observable, writable properties using the observableValue.select() function
    • ViewModel bind has optional parameter forceObjectProperty to avoid creating IntegerProperty for ints etc, so you can have nullable values
    • TableView.onEditCommit() handler fires when a cell is edited. No need to manage domain object value, just add your business logic
    • Fixed scope support. DefaultScope(MyController::class) or MyController::class.scope(DefaultScope)
    • TableColumn hasClass/addClass/removeClass/toggleClass supports type safe stylesheets
    • Lots of functions that earlier accepted Double now accept Number
    • TableView.enableCellEditing() makes table editable and enables cell selection
    • TableView.regainFocusAfterEdit() - make sure TableView doesn't look focus after cell edit
    • TableColumn.makeEditable(converter) - supply specific converter for editable fields
    • TableColumn.converter(converter) - supply specific converter for read only text fields
    • TableColumn.makeEditable() supports BigDecimal
    • Added scope.set(injectable) as easier alternative to setInScope(injectable, scope)
    • tableview builder that takes ObservableValue<ObservableList<T>>, supporting automatic rebind when items change
    • vbox and hbox builders supports any Number as spacing parameter, not just Double
    • runAsync exposes TaskStatus model for binding towards task states: running, message, title, progress, value
    • runAsync now run in the context of Task so you can access updateMessage() etc
    • progressbar and progressindicator builders binds to Property<Number> instead of Property<Double> to support DoubleProperty
    • Added insets() builder
    • Fixed a race condition in Slideshow with overlapping transitions (https://github.com/edvin/tornadofx/issues/225)
    • Node onHover { doSomething() } helper, param is boolean indicating hover state
    • Node builder bindings: disableWhen, enableWhen, visibleWhen, hiddenWhen, removeWhen
    • ObservableValue.toBinding() converts observable boolean to BooleanBinding
    • TableCell.useCombobox now supports every kind of Property (bug)
    • Observable padding properties for Region paddingXXXProperty (top/right/bottom/left/vertical/horizontal/all)
    • Padding vars for Region: `paddingXXX' (top/right/bottom/left/vertical/horizontal/all)
    • Added proxyprop helper to create proxied properties
    • DataGrid maxCellsInRow property (also CSS styleable as -fx-max-cells-in-row)
    • Added DataGrid.asyncItems to load items async with more concise syntax
    • Added DataGrid.bindSelected to bind selected item to another property or ViewModel
    • Fixed a ViewModel binding bug causing errors if external changes were made to a bound facade
    • Added squeezebox builder. SqueezeBox is an accordion that allows multiple open titledpanes, added using fold()
    • cellCache supports builders. Earlier, builders would be appended to the ListView, creating undesirable results
    • Scene.reloadViews() is removed from the public API, no need to call it manually
    • titledpane builder now accepts op parameter like every other builder. node parameter is now optional
    • Fieldset.wrapWidth is now Number instead of Double
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.6.0.jar(1.55 MB)
  • v1.5.9(Dec 24, 2016)

    This release introduces the EventBus and lots of small improvements and bug fixes.

    • UIComponent has isdockedProperty and isDocked boolean telling you if the ui component is currently docked
    • Added CSS elements to type safe stylesheets so you can now target f.ex HBox even if it doesn't have a CSS class
    • Pass parameters to ui components using inject/find. Inject params via val myParam : Int by param() in target view.
    • booleanBinding and stringBinding now adds observable receiver as dependency
    • Eventbus: FXEvent class with subscribe(), unsubscribe and fire functions (https://edvin.gitbooks.io/tornadofx-guide/content/15.%20EventBus.html)
    • InternalWindow is public, closeModal() will also close InternalWindow
    • setInScope(value, scope) allows you to preemptively configure an injectable property
    • Allow Labeled.bind() to work on ObservableValue instead of just Property
    • HttpClientEngine now adds default json headers to request
    • Fixed Bug: Unconsumed POST requests are not posted to the server completely
    • Add Connection: Keep-Alive and User-Agent headers to the default rest client engine
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.5.9.jar(1.38 MB)
  • v1.5.8(Nov 24, 2016)

    Lots of improvements and some new control additions in this release :)

    • WritableValue.assignIfNull(creatorFn) assigns to the value by calling creator unless it is already non-null
    • Button.accelerator(KeyCombination) adds shortcuts to buttons (https://github.com/edvin/tornadofx/issues/205)
    • Slideshow component and slideshow builder
    • openInternalWindow(SomeOtherView::class) opens a window ontop of the current scene graph
    • bindStringProperty respects given format (https://github.com/edvin/tornadofx/issues/210)
    • Proxy support for Rest client (Set client.proxy = Proxy())
    • Pane builder (https://github.com/edvin/tornadofx/issues/208)
    • Iterable.style will apply styles to all elements in collection
    • Added Node.alignment property that knows how to apply alignment depending on the parent
    • Added Node.margin property that knows how to apply margin depending on the parent
    • canvas builder
    • All constraint builders no longer set default values for properties that are not overridden
    • Added canvas() builder
    • Kotlin 1.0.5-2
    • Added stackpaneConstraints builder (margin/alignment) (https://github.com/edvin/tornadofx/issues/206)
    • Added Node.hgrow and Node.vgrow properties (https://github.com/edvin/tornadofx/issues/204)
    • ComboBox.cellFormat also formats button cell by default with option to override
    • UIComponent.openWindow() opens a new modeless Window
    • TreeView.bindSelected(itemProperty) and TreeView.bindSelected(itemViewModel)
    • Rest POST supports InputStream (https://github.com/edvin/tornadofx/pull/200)
    • Removed deprecated findFragment - use find instead
    • ViewModel.ignoreDirtyStateProperties list of properties that should not be considered when calculating dirty state
    • Removed deprecated replaceWith overloads (https://github.com/edvin/tornadofx/issues/199)
    • Scope support
    • ViewModel is now Component and Injectable so it supports injection.
    • addClass/removeClass/toggleClass now also works for pseudo classes (https://github.com/edvin/tornadofx/issues/198)
    • ItemViewModel().bindTo(listCellFragment)
    • resources.stream("some-resource") locates InputStream for resource
    • Added custom renderers to custom CSS Properties (https://github.com/edvin/tornadofx/issues/203)
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.5.8.jar(1.33 MB)
  • v1.5.7(Oct 21, 2016)

    Another release with lots of small improvements and bug fixes.

    • Fixed LayoutDebugger not showing debugged scene correctly (https://github.com/edvin/tornadofx/issues/192)
    • App.shouldShowPrimaryStage() can be used to initially hide the primary stage
    • Node.onDoubleClick handler
    • chooseDirectory function
    • ListView.bindSelected(itemProperty) and ListView.bindSelected(itemViewModel)
    • TableView.bindSelected(itemProperty) and TableView.bindSelected(itemViewModel)
    • Added ItemViewModel to reduce boiler plate for ViewModels with one source object
    • SortedFilteredList now supports editing writeback to the underlying observable list
    • View.replaceWith now updates scene property to support Live Views (https://github.com/edvin/tornadofx/issues/191)
    • ViewModel bind return value is now optional to support eventually available items
    • ViewModel detects changes to the source object and applies to the model counterpart automatically
    • ViewModel bind(autocommit = true) { .. } option
    • Mnemonic in Field labels (form -> field -> input.mnemonicTarget())
    • Added ItemFragment and ListCellFragment. Will add TableCellFragment etc shortly.
    • Added TreeView.cellDecorator
    • Node.hide and Node.show
    • Node.toggleClass(class, observableBooleanValue)
    • Removed cell as this for cellCache. The cell could change, so taking it into account was a mistake.
    • App MainView parameter can now be a Fragment as well as View
    • ListView cellCache provider to create a cached graphic node per item
    • Kotlin 1.0.4
    • The di() delegate no longer calls out to the DIContainer for every access, effectively caching the lookup
    • The fxid() delegate can now inject any type, not just EventTarget subclasses
    • Added non-null onChange overrides for primitive ObservableValues
    • Fixed bug with Node.fade reversed animations (was also affecting ViewTransitions)
    • Deprecated confusing CSS add function if favor of and
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.5.7.jar(1.24 MB)
  • v1.5.6(Sep 19, 2016)

    This is another feature packed release with features like the DataGrid component, TableView Row Expander, TableView SmartResize Policy, and lots of all round improvements and fixes. Here is the complete changelog:

    • ViewModel.onCommit() function that will be called after a successful commit
    • TableView SmartResize Policy (https://github.com/edvin/tornadofx/wiki/TableView-SmartResize)
    • dynamicContent builder that will replace content in a Node when an observable value changes
    • Alternative TableView.column builder with auto-conversion to observable value (column("Title", ReturnType::class) { value { it.value.somePropertyOrValue })
    • DataGrid component
    • TableColumn cellCache provider to create a cached graphic node per item
    • Padding shortcuts (paddingRight, paddingLeft, paddingTop, paddingBottom) to Region
    • TableView support for Nested Columns (nestedColumn(title) { // add child columns here })
    • TableView support for expanded row node (rowExpander { // create node to show on expand here }) (https://edvin.gitbooks.io/tornadofx-guide/content/5.%20Builders%20II%20-%20Data%20Controls.html#row-expanders)
    • Fixed bug where image URLs defined in CSS were rendered wrong
    • Added support for skipping snake-casing in CSS rules (names still have to be valid css identifiers)
    • Fixed bug where CSS selectors defined with strings would have their capitalization changed (".testThing" => ".test-thing", cssclass("testThing") => .test-thing)
    • Updated the ViewTransition code to be more flexible (including now working with any Node, not just Views and Fragments).
      • Also added several new built in ViewTransitions
    • Added new Node animation helper functions for various transformations
    • FXML files can now contain fx:controller attribute to help with content assist, if hasControllerAttribute = true is passed to the fxml delegate (https://github.com/edvin/tornadofx/issues/179)
    • Fix exception in chooseFile when user cancels in Multi mode
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.5.6.jar(1.20 MB)
  • v1.5.5(Aug 19, 2016)

    • Stylesheets can be loaded via ServiceLoader (META-INF/services/tornadofx.Stylesheet with reference to the stylesheet class)
    • Default constructor was re-added to tornadofx.App to support Run View in IDEA Plugin
    • resizeColumnsToFitContent has afterResize callback parameter
    • SortedFilteredList.asyncItems function
    • SortedFilteredList can now be assigned as items to tableview/listview builder without calling bindTo
    • DefaultErrorHandler.filter listens to uncaught errors and can consume them to avoid the default error dialog.
    • json.add(key, JsonModel) automatically converts to JSON
    • CSS DSL now supports imports through constructor parameters. e.g. class DialogStyle : StyleSheet(BaseStyle::class) { ... }
    • Fixed a bug in View.replaceWith which caused the whole scene to change even when for sub views
    Source code(tar.gz)
    Source code(zip)
  • v1.5.4(Aug 2, 2016)

    This release only fixes an issue with type safe stylesheets in 1.5.3, namely that importStylesheet would fail unless an OSGi runtime was available on the classpath. These were the changes in 1.5.3:

    This release brings some great syntax changes that further reduces boiler plate. You can now define a View like this:

    class CustomerEditor : View("Edit Customer") {
        override val root = borderpane {
        }
    }
    

    We finally have great OSGi support - a demo screencast will follow shortly.

    Below is a complete list of all improvements and bug fixes.

    Important note: This version not binary compatible, so make sure you do a full rebuild of your project. We've had reports some "sticky" IDEA cache, so try to restart your IDE if a rebuild doesn't do it.

    Added

    • App.createPrimaryScene overridable function to specify how the scene for the primary View is created
    • OSGI manifest metadata
    • LayoutDebugger can edit new Node properties: spacing
    • Stylesheets can be dynamically added at runtime and will affect all active scenes
    • Convenience methods for creating bindings on any object. e.g. stringBinding(person, person.firstNameProperty, person.lastNameProperty) { "$firstName, #lastName" }
    • View/Fragment takes optional title in constructor

    Changed

    • UIComponent.showModal now supports reopening even if modalStage was never removed
    • fieldset block now operates on an HBox instead of Pane so you can write alignment = Pos.BASELINE_RIGHT to right-align buttons etc
    • Set modalStage before showAndWait() (https://github.com/edvin/tornadofx/pull/151)
    • Parent.find and UIComponent.find renamed to lookup for better alignment with JavaFX lookup and to avoid confusion with find(View::class)
    • Improved BorderPane builders, they also now accept UIComponent references instead of instances
    • Builders now operate on EventTarget instead of Pane and as a result, many builders have improved syntax and functionality
    • Reduced boilerplate for App creation (you can now use class MyApp : App(MyView::class, Styles::class)
    • ViewModel commit and rollback run on the UI thread because decorators might be invoked
    • ViewModel commit accepts a function that will be run if the commit is successful
    • find can now also find Fragments, so findFragment is deprecated
    • lookup takes an optional op that operates on the UIComponent it found
    • TreeTableView/TableView.populate accepts any kind of Iterable<T> instead of List
    Source code(tar.gz)
    Source code(zip)
    tornadofx-1.5.4.jar(1.03 MB)
Owner
Edvin Syse
Edvin Syse
CPU Scheduler Visualization written in Kotlin TornadoFX

CPU-Scheduler-Visualization CPU Scheduler Visualization written in Kotlin TornadoFX 목적 CPU Secheduling algorithm을 시각화해주는 프로그램입니다. FCFS, NonPreemptiveS

null 0 Apr 25, 2022
A JavaFX app to visualize RNA alignments from Rfam database.

Kaknas Kaknas is a JavaFX graphical tool to visualize and manipulate RNA alignments from the Rfam database. It is powered with RNArtistCore. For a giv

Fabrice Jossinet 5 Apr 7, 2022
This provides the javafx runtimes for windows, linux, and mac os x86 platforms for Ignition

ignition JavaFX Provider This provides the javafx runtimes for windows, linux, and mac os x86 platforms for Ignition Steps to use run gradlew build st

Jonathan Coffman 2 Oct 17, 2022
Cross-platform framework for building truly native mobile apps with Java or Kotlin. Write Once Run Anywhere support for iOS, Android, Desktop & Web.

Codename One - Cross Platform Native Apps with Java or Kotlin Codename One is a mobile first cross platform environment for Java and Kotlin developers

Codename One 1.4k Jan 9, 2023
Android MVVM framework write in kotlin, develop Android has never been so fun.

KBinding 中文版 Android MVVM framework write in kotlin, base on anko, simple but powerful. It depends on my another project AutoAdapter(A library for sim

Benny 413 Dec 5, 2022
A framework for writing composable parsers based on Kotlin Coroutines.

Parsus A framework for writing composable parsers based on Kotlin Coroutines. val booleanGrammar = object : Grammar<BooleanExpression>() { val ws

Aleksei Semin 28 Nov 1, 2022
Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing functionality and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.), inspired by Badoos RIBs fork of the Uber RIBs framework

Decompose Please see the project website for documentation and APIs. Decompose is a Kotlin Multiplatform library for breaking down your code into life

Arkadii Ivanov 819 Dec 29, 2022
Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotchaphan Muangsan 3 Nov 15, 2022
Framework for quickly creating connected applications in Kotlin with minimal effort

Ktor is an asynchronous framework for creating microservices, web applications and more. Written in Kotlin from the ground up. import io.ktor.server.n

ktor.io 10.7k Jan 9, 2023
A modular object storage framework for Kotlin multiplatform projects.

ObjectStore A modular object storage framework for Kotlin multiplatform projects. Usage ObjectStore provides a simple key/value storage interface whic

Drew Carlson 4 Nov 10, 2022
This is powerful android framework

FlairFramework This is an android framework for build complex application with different architectures (MVC ready/MVP/MVVM/MVI ets). It's create on to

Alexandr Minkin 31 Nov 29, 2021
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Cossack Labs 1.6k Jan 8, 2023
General purpose parsing framework. Simplify parsing of text

General purpose parsing framework. Simplify parsing of text. Allows capture complex nested formats with simple and human-readable syntax.

Roman 1 Nov 16, 2021
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
Ivy FRP is a Functional Reactive Programming framework for declarative-style programming for Android

FRP (Functional Reactive Programming) framework for declarative-style programming for Andorid. :rocket: (compatible with Jetpack Compose)

null 8 Nov 24, 2022
A sample application that build with combine use Clean Architecture framework and Github API

The Github Example Introduction This is a sample application that build with combine use Clean Architecture framework and Github API (https://develope

Nguyễn Hùng An 2 Aug 12, 2022
Run Kotlin/JS libraries in Kotlin/JVM and Kotlin/Native programs

Zipline This library streamlines using Kotlin/JS libraries from Kotlin/JVM and Kotlin/Native programs. It makes it possible to do continuous deploymen

Cash App 1.5k Dec 30, 2022
A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

common sense OSS 0 Jan 20, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

Gérard Paligot 98 Dec 15, 2022