Tornadofx: No ability to define custom CSS properties.

Created on 3 Nov 2016  路  25Comments  路  Source: edvin/tornadofx

JavaFX allows you to define custom css properties.
It would be nice if people could add their own typesafe css props for Stylesheet classes ad-hoc.

Most helpful comment

I've come up with a working method. cssproperty<T>() now also accepts a (T) -> String as a custom renderer. For example:

enum class Bool { TRUE, FALSE, FILE_NOT_FOUND }

...

val renderedProp by cssproperty<String> { "${it.toUpperCase()}!!!" }
val renderedBool by cssproperty<Bool> { it.name }

...

label {
    renderedProp.value = "bang"
    renderedBool.value = Bool.FILE_NOT_FOUND
}

Would be rendered as:

.label {
    rendered-prop: BANG!!!;
    rendered-bool: FILE_NOT_FOUND;
}

Check out the branch

All 25 comments

You can add typesafe properties ad-hoc, though the syntax is a little different. You set it with prop.value = whatever instead of prop = whatever. For example:

class MyApp : App(MyView::class, Styles::class) {
    class MyView : View("Custom CSS Properties Demo") {
        override val root = hbox {
            addClass(Styles.box)
        }
    }

    class Styles : Stylesheet() {
        companion object {
            val box by cssclass()
            val bg by cssproperty<MultiValue<Paint>>("-fx-background-color")  // Define custom property
        }

        init {
            box {
                bg.value += Color.RED  // Set custom property
                prefWidth = 500.px
                prefHeight = 300.px
            }
        }
    }
}

produces

capture

In this case I did refer the property to an already existing property, but you just need to change "-fx-background-color" to whatever your property selection string is and the type (MultiValue<Paint> in this case) and you're golden.


(Note that you can't define properties for a specific class as not even the built in ones do that. It's a limitation of Kotlin's extension method scoping. If this KEEP gets implemented cleanly enough, we may be able to fix that.)

As far as your original question goes, can you point me to where -fx-button-type is documented? It's not in the official CSS Reference. Sadly, there seems to be a lot of CSS that isn't in there, so I'm still missing quite a bit.

@thomasnield Do you know if creating custom properties is covered in the guide?

I refer to the custom css properties rather then stock ones. You can add your own very custom CSS property handling to your views in JavaFX, but then you can't use them in typesafe manner in Stylesheet class.

cssproperty<ButtonType>("-fx-button-type") almost did the trick. Now my problem is it lowercases value, which it shouldn't since it's a enum which is parsed by Java back. I didn't found any way to control this behaviour.

Actually, I think your problem is the opposite. Lowercase enums work fine, but ButtonType isn't an enum. It's just a class with a bunch of public static final ButtonTypes on it. It seems that, while we do support custom properties, we don't support rendering custom types. I'll have to dig into this more.

Or are you referring to a custom ButtonType enum? (I'm looking at javafx.scene.control.ButtonType)

Maybe we could add an extension to the renderer so you can plug in a handler that returns true if it rendered the custom type for example?

@edvin That's a good idea

No, ButtonType is a enum, defined in library as:

    public static enum ButtonType{FLAT, RAISED};

I'm referring to the custom enum ButtonType, not javafx built-in one.

@dant3 Alright, sorry. I was looking at JavaFX's built in ButtonType. Currently, you can use the unsafe bypass (unsafe("-fx-button-type", raw("FLAT")) would render as -fx-button-type: FLAT;), though I'm not sure why the enum wasn't working. I'll look into it more. What library are you using?

It's JFoenix.
In their demos you can find ButtonDemo, which uses CSS, and it defines custom button property in this css file.

I can confirm it is a case issue, which is both interesting and annoying. unsafe("-fx-button-type", raw("RAISED")) works just fine, but for some reason using cssproperty<JFXButton.ButtonType>("-fx-button-type") (which renders lowercase) does not.

This is annoying since all of JavaFX's internal enums are expected to be in snake case in CSS.

@edvin Do you think we need to add special support for all of JavaFX's internal enums, while other enums are rendered as-is?

Using buttonType.value = JFXButton.ButtonType.RAISED:

.jbt {
    -fx-font-size: 14px;
    -fx-background-color: rgba(77, 102, 204, 1);
    -fx-pref-width: 200px;
    -fx-text-fill: rgba(255, 255, 255, 1);
    -fx-button-type: raised;
}

capture

Using unsafe("-fx-button-type", raw("RAISED")):

.jbt {
    -fx-font-size: 14px;
    -fx-background-color: rgba(77, 102, 204, 1);
    -fx-pref-width: 200px;
    -fx-text-fill: rgba(255, 255, 255, 1);
    -fx-button-type: RAISED;
}

capture

Unfortunately javafx does not provides it's conversion code as a public API, so library authors left out on their own with this conversions. However there is no strict requirement on that.
IMO it would be nice to be able to supply custom value renderer, having javafx default behaviour as default value.

@dant3 Yes, it's been a thorn in my side for a while now. I still can't get dashed borders to work as they say they should.

That sounds reasonable. Hopefully I'll get time to implement custom renderers soon.

I've come up with a working method. cssproperty<T>() now also accepts a (T) -> String as a custom renderer. For example:

enum class Bool { TRUE, FALSE, FILE_NOT_FOUND }

...

val renderedProp by cssproperty<String> { "${it.toUpperCase()}!!!" }
val renderedBool by cssproperty<Bool> { it.name }

...

label {
    renderedProp.value = "bang"
    renderedBool.value = Bool.FILE_NOT_FOUND
}

Would be rendered as:

.label {
    rendered-prop: BANG!!!;
    rendered-bool: FILE_NOT_FOUND;
}

Check out the branch

That looks fantastic, just what we need!

Implemented, so I'll close this.

@edvin This hasn't been merged into master yet. Did you want it in there, or did you want to wait till you can test it better?

Ah, sorry. I think it would be fine to merge it. In the future I'd like to see if we can avoid the .value= assignment for custom properties, but this is in line with what we already have for now, so I think it's good to merge it.

The .value= isn't something I changed. That's what was already there for custom properties. As far as the API is concerned, the only change I made was the addition of the closure block to the cssproperty delegate.

I know :) Will you merge and add a line to the changelog for this?

Will do

Edit: merged

Perfect!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AlmasB picture AlmasB  路  8Comments

Mosch0512 picture Mosch0512  路  4Comments

eibens picture eibens  路  4Comments

elliotcm picture elliotcm  路  7Comments

Stars-One picture Stars-One  路  6Comments