Qt Quick Controls - StyleKit

A PySide6 application that demonstrates the analogous example in Qt StyleKit Example.

This example shows how to style Qt Quick Controls applications using Qt Labs StyleKit.

It includes several styles that each demonstrate different aspects of styling:

  • Plain - A minimal style with only the basics

  • Haze - An advanced style with multiple themes

  • Vitrum - A style targeting VR environments

The example demonstrates, among other things, how to:

  • Implement and switch between different styles.

  • Implement support for light and dark themes, as well as additional themes such as high-contrast.

  • Use StyleVariation to provide alternative styling for parts of the application.

  • Apply shader-based visual effects to the controls.

  • Build custom controls using CustomControl and StyleReader.

  • Interact with a style at runtime, for example to change the theme or adjust style properties like the background radius.

StyleKit Screenshot

Download this example

"""
PySide6 port of StyleKit Quick Controls example from Qt v6.x
"""
import sys
from pathlib import Path
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine

if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    app.setOrganizationName("QtProject")
    app.setApplicationName("StyleKit")
    engine = QQmlApplicationEngine()

    engine.addImportPath(Path(__file__).parent)
    engine.loadFromModule("StyleKitControlsExample", "Main")

    if not engine.rootObjects():
        sys.exit(-1)

    exit_code = app.exec()
    del engine
    sys.exit(exit_code)
import QtQuick
import QtQuick.Layouts
import Qt.labs.StyleKit
import "styles"

ApplicationWindow {
    id: app
    width: 1048
    height: 800
    visible: true
    title: qsTr("StyleKit")

    // Set the initial style:
    StyleKit.style: hazeStyle

    // Instantiate the available styles. The user can switch between them
    // at runtime, and each style provides its own set of themes.
    Haze { id: hazeStyle }
    Vitrum { id: vitrumStyle }
    Plain { id: plainStyle }
    Fusion { id: fusionStyle }

    property real spacing: 10
    StyleKit.transitionsEnabled: transitionsEnabled.checked

    menuBar: MenuBar {
        id: appMenuBar

        Menu {
            title: qsTr("File")
            Action { text: qsTr("New...") }
            Action { text: qsTr("Open...") }
            Action { text: qsTr("Save") }
            Action { text: qsTr("Save As...") }
            MenuSeparator { }
            Action {
                text: qsTr("Quit")
                onTriggered: Qt.exit(0)
                shortcut: StandardKey.Quit
            }
        }

        Menu {
            title: qsTr("Edit")
            Action { text: qsTr("Cut") }
            Action { text: qsTr("Copy") }
            Action { text: qsTr("Paste") }
        }

        Menu {
            title: qsTr("Help")
            Action { text: qsTr("About") }
        }
    }

    ScrollView {
        id: scrollView
        anchors.fill: parent
        contentHeight: content.height + 40

        ColumnLayout {
            id: content
            x: 10
            y: app.spacing * 2
            transformOrigin: Item.TopLeft
            spacing: app.spacing * 2

            GroupBox {
                title: "Buttons"
                ColumnLayout {
                    RowLayout {
                        spacing: app.spacing
                        Button {
                            text: "Normal"
                        }

                        Button {
                            text: "Checkable"
                            checkable: true
                        }

                        Button {
                            text: "Disabled"
                            enabled: false
                        }
                    }

                    RowLayout {
                        spacing: app.spacing
                        Button {
                            text: "Flat"
                            flat: true
                            checkable: true
                        }

                        RoundButton {
                            text: "Round"
                        }

                        DelayButton {
                            text: qsTr("DelayButton")
                        }
                    }
                }
            }

            GroupBox {
                title: "CheckBoxes and RadioButtons"
                GridLayout {
                    rowSpacing: app.spacing
                    columnSpacing: app.spacing
                    columns: 3

                    CheckBox {
                        text: "Mango"
                        checked: true
                    }

                    CheckBox {
                        text: "Avocado"
                    }

                    CheckBox {
                        text: "Banano"
                        checked: true
                    }

                    RadioButton {
                        text: "Pasta"
                    }

                    RadioButton {
                        text: "Lasagna"
                        checked: true
                    }

                    RadioButton {
                        text: "Burrita"
                    }
                }
            }

            GroupBox {
                title: "Text inputs"
                RowLayout {
                    spacing: app.spacing

                    TextField {
                        id: tf1
                        placeholderText: "Potato"
                    }

                    TextField {
                        id: tf2
                        placeholderText: "Tomato"
                    }
                }
            }

            GroupBox {
                title: "Misc"
                GridLayout {
                    rowSpacing: app.spacing
                    columnSpacing: app.spacing
                    columns: 3

                    Switch {
                        checked: true
                        text: "Switch 1"
                    }

                    SpinBox {
                        id: spinBox1
                        value: 42
                    }

                    ComboBox {
                        id: comboBox1
                        model: ["One", "February", "Aramis", "Winter", "Friday"]
                    }
                }
            }

            GroupBox {
                title: "Sliders"
                RowLayout {
                    spacing: app.spacing

                    ColumnLayout {
                        Slider {
                            id: slider1
                            from: 0
                            to: 10
                            value: 5
                        }

                        RangeSlider {
                            id: rangeSlider1
                            from: 0
                            to: 10
                            first.value: 2
                            second.value: 8
                        }
                    }

                    Slider {
                        id: slider2
                        from: 0
                        to: 10
                        value: 2
                        orientation: Qt.Vertical
                    }

                    RangeSlider {
                        id: rangeSlider2
                        from: 0
                        to: 10
                        first.value: 2
                        second.value: 8
                        orientation: Qt.Vertical
                    }
                }
            }

            GroupBox {
                title: "Dials"
                RowLayout {
                    spacing: app.spacing * 2

                    ColumnLayout {
                        Dial {
                            id: dialCircular
                            from: 0
                            to: 10
                            value: 5
                            inputMode: Dial.Circular
                        }
                        Label {
                            text: "Circular"
                            Layout.alignment: Qt.AlignHCenter
                        }
                    }

                    ColumnLayout {
                        Dial {
                            id: dialHorizontal
                            from: 0
                            to: 10
                            value: 5
                            inputMode: Dial.Horizontal
                        }
                        Label {
                            text: "Horizontal"
                            Layout.alignment: Qt.AlignHCenter
                        }
                    }

                    ColumnLayout {
                        Dial {
                            id: dialVertical
                            from: 0
                            to: 10
                            value: 5
                            inputMode: Dial.Vertical
                        }
                        Label {
                            text: "Vertical"
                            Layout.alignment: Qt.AlignHCenter
                        }
                    }
                }
            }

            GroupBox {
                title: "Popups"
                RowLayout {
                    spacing: app.spacing

                    Button {
                        text: "Open Popup"
                        onClicked: popup.open()
                    }
                }
            }

            GroupBox {
                title: "Variations"
                StyleVariation.variations: ["mini"]
                ColumnLayout {
                    spacing: app.spacing * 2
                    Text {
                        visible: StyleKit.style === hazeStyle
                        text: "These controls are affected by an Instance Variation named 'mini'"
                    }
                    RowLayout {
                        spacing: app.spacing

                        TextField {
                            placeholderText: "Mini zucchini"
                        }

                        Switch {
                            checked: true
                        }

                        Button {
                            // This button will be affected by both an "alert" and a "mini" variation
                            StyleVariation.variations: ["alert"]
                            text: "Alert!"
                        }

                        CheckBox {
                            text: "Baninis"
                            checked: true
                        }

                        Slider {
                            value: 0.5
                        }
                    }
                    Frame {
                        Layout.preferredHeight: 120
                        Layout.fillWidth: true
                        Column {
                            spacing: 20
                            anchors.fill: parent
                            Text {
                                visible: StyleKit.style === hazeStyle
                                anchors.horizontalCenter: parent.horizontalCenter
                                text: "Frame also has a Type Variation that affects Button"
                            }
                            Button {
                                anchors.horizontalCenter: parent.horizontalCenter
                                text: "Button"
                            }
                        }
                     }
                }
            }

            GroupBox {
                title: "Custom controls"
                RowLayout {
                    spacing: app.spacing

                    CustomButtonImplementation {}
                    CustomButtonImplementation {}
                }
            }
        }

        // Settings menu

        GroupBox {
            id: menu
            anchors.right: parent.right
            anchors.rightMargin: 10
            contentWidth: menuContents.implicitWidth
            contentHeight: menuContents.implicitHeight
            title: "Settings"
            y: app.spacing * 2

            GridLayout {
                id: menuContents
                columns: 2
                rowSpacing: app.spacing
                columnSpacing: app.spacing

                Label { text: "Style" }
                ComboBox {
                    id: styleSelector
                    textRole: "text"
                    valueRole: "value"
                    currentValue: StyleKit.style
                    model: [
                        { value: hazeStyle, text: "Haze" },
                        { value: plainStyle, text: "Plain" },
                        { value: vitrumStyle, text: "Vitrum" },
                        { value: fusionStyle, text: "Fusion" }
                    ]
                    onCurrentTextChanged: {
                        StyleKit.style = model[currentIndex].value;
                        themeSelector.currentValue = StyleKit.style.themeName
                        themeSelector.model = StyleKit.style.availableThemeNames
                    }
                    Component.onCompleted: {
                        themeSelector.currentValue = StyleKit.style.themeName
                        themeSelector.model = StyleKit.style.availableThemeNames
                    }
                }

                Label { text: "Theme" }
                ComboBox {
                    id: themeSelector
                    onCurrentTextChanged: StyleKit.style.themeName = currentText
                }

                Label { text: "Radius" }
                Slider {
                    Layout.maximumWidth: 150
                    from: 0
                    to: 20
                    value: StyleKit.style.control.background.radius
                    onValueChanged: {
                        // Ensure we don't set the value if the style already has the same value
                        // set, or if that value is out-of-range WRT the slider. In both cases,
                        // this would lead to a binding loop.
                        let styleValue = StyleKit.style.control.background.radius
                        if (styleValue === value || styleValue < from || styleValue > to)
                            return
                        StyleKit.style.abstractButton.background.radius = value
                        StyleKit.style.groupBox.background.radius = value
                    }
                }

                Label { text: "Transitions enabled" }
                Switch {
                    id: transitionsEnabled
                    checked: true
                }

                Label { text: "Accent color" }
                ComboBox {
                    id: accentColor
                    model: ["darkseagreen", "plum", "sandybrown", "slateblue"]
                    onCurrentTextChanged: app.palette.accent = currentText
                }
            }
        }
    }

    Popup {
        id: popup
        anchors.centerIn: parent
        closePolicy: Popup.NoAutoClose
        popupType: Popup.Window

        ColumnLayout {
            anchors.centerIn: parent
            spacing: app.spacing * 2

            Label {
                text: qsTr("A Label in a Popup")
                Layout.alignment: Qt.AlignHCenter
            }

            Button {
                text: qsTr("Close Popup")
                Layout.alignment: Qt.AlignHCenter
                Layout.fillWidth: false
                onClicked: popup.close()
            }
        }
    }

    // In addition to Qt Quick Controls, it's also possible to
    // define and style your own custom controls.

    component CustomButtonImplementation : Rectangle {
        implicitWidth: fancyButton.background.width + fancyButton.leftPadding + fancyButton.rightPadding
        implicitHeight: fancyButton.background.height + fancyButton.topPadding + fancyButton.bottomPadding
        radius: fancyButton.background.radius
        border.color: fancyButton.background.border.color
        border.width: fancyButton.background.border.width
        color: fancyButton.background.color
        scale: fancyButton.background.scale

        StyleReader {
            id: fancyButton
            controlType: hazeStyle.fancyButton
            hovered: hoverHandler.hovered
            pressed: tapHandler.pressed
            palette: app.palette
        }

        Text {
            anchors.centerIn: parent
            font.pixelSize: 15
            text: "Custom Button"
        }

        HoverHandler {
            id: hoverHandler
        }

        TapHandler {
            id: tapHandler
            onTapped: {
                // Change the background color of all controls whose
                // controlType matches fancyButton.type.
                let fancyButtons = StyleKit.style.theme.getControlStyle(fancyButton.type)
                if (fancyButtons) // Only the Haze style defines a fancyButton
                    fancyButtons.background.color = "yellowgreen"
            }
        }
    }
}
import QtQuick
import Qt.labs.StyleKit

Style {
    id: style

    fonts {
        system {
            family: "Courier New"
            pointSize: 12
        }
        textField.bold: true
        label.bold: true
    }

    control {
        // 'control' is the fallback for all the controls. Any properties that are not
        // overridden by a specific control underneath will be read from here instead.
        padding: 8

        background {
            // Disable drop shadow on the background by default, and enable it per
            // control type below instead
            shadow.visible: false
        }

        handle {
            width: 25
            height: 25
            radius: 25
            gradient: Gradient {
                GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
                GradientStop { position: 1.0; color: Qt.alpha("black", 0.2)}
            }
            shadow {
                opacity: 0.8
                scale: 1.1
            }
        }

        indicator {
            foreground.margins: 2
        }

        transition: Transition {
            StyleAnimation {
                animateColors: true
                animateBackgroundShadow: true
                animateHandleShadow: true
                duration: 300
            }
        }

        hovered {
            // For this style, we don't want to show any transitions when entering or while inside
            // the 'hovered' state. This makes the control light up immediately when hovered, but
            // fade out more slowly when returning to the 'normal' state. We therefore override
            // 'transition' and set it to null.
            transition: null
        }
    }

    abstractButton {
        // 'abstractButton' is the fallback for all button types such as 'button', 'checkBox',
        // 'radioButton', 'switch', etc. This is a good place to style the properties they all
        // have in common. Any properties not set here will fall back to those defined in 'control'.
        background {
            width: 100
            height: 30
            opacity: 0.8
            radius: 8

            shadow {
                visible: true
                opacity: 0.8
                scale: 1.1
            }

            gradient: Gradient {
                GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
                GradientStop { position: 1.0; color: Qt.alpha("black", 0.2)}
            }
        }
    }

    button {
        // Here you can override the style for a Button. The properties you set here apply only
        // to a Button, not to for example a CheckBox. Any properties not set here will fall back
        // to those defined in 'abstractButton'.
        pressed {
            background.scale: 0.95
        }
    }

    delayButton {
        padding: 0
        indicator {
            radius: 8
            foreground {
                margins: 0
                radius: 8
            }
        }
    }

    flatButton {
        background.gradient: null
    }

    checkBox {
        transition: Transition {
            NumberAnimation {
                // Using a StyleAnimation for transitions is optional. A StyleAnimation can be
                // used in parallel with other animations, or not used at all. Here we choose to use
                // a NumberAnimation instead to animate the 'checked' image so that it bounces.
                properties: "indicator.foreground.leftMargin, indicator.foreground.rightMargin"
                            + ", indicator.foreground.topMargin, indicator.foreground.bottomMargin"
                easing.type: Easing.OutBounce
                duration: 500
            }
        }
        hovered {
            transition: null
            indicator.foreground.margins: -15
        }
    }

    comboBox {
        background.width: 200
        pressed.background.scale: 1.0
    }

    dial {
        handle.width: 15
        handle.height: 15
        indicator.foreground.margins: 0
    }

    pane {
        // 'pane' is the fallback for all pane based controls, such as 'frame' and 'groupBox'.
        //  Any properties not set here will fall back to those defined in 'control'.
        spacing: 5
        padding: 20
        background {
            border.width: 0
            width: 200
            height: 200
            shadow.visible: false
        }
    }

    groupBox {
        background.topMargin: 20
        background.height: 30
        text.bold: true
    }

    menu {
        background.width: 120
    }

    menuBar {
        padding: 1
        background.height: 30
    }

    menuBarItem {
        text.bold: true
        background {
            height: 30
            width: 30
        }
        transition: null
    }

    menuItem {
        padding: 4
        background.height: 20
        transition: null
    }

    menuSeparator {
        padding: 4

        background {
            width: 120
            height: 1
            border.width: 0
        }

        indicator {
            height: 1
            width: 120
            border.width: 0

            foreground.margins: 0
            foreground.visible: false
        }
    }

    radioButton {
        indicator {
            foreground {
                margins: 4
                radius: 25 / 2
                border.width: 0
            }
        }
    }

    roundButton {
        background.radius: 255
    }

    scrollBar {
        padding: 2
        background.visible: false
    }

    scrollIndicator {
        padding: 0
        indicator.foreground.margins: 0
    }

    slider {
        background.width: 180
        indicator {
            height: 8
            radius: 8
            foreground {
                radius: 8
            }
        }
        vertical {
            background {
                width: 50
                height: 150
            }

            indicator {
                width: 8
            }
        }
    }

    spinBox {
        padding: 4
        background {
            width: 100
            scale: 1
        }
        indicator.height: 24
    }

    switchControl {
        indicator {
            width: 60
            height: 30
            radius: 5
            foreground.radius: 4
        }
        handle {
            leftMargin: 3
            rightMargin: 3
        }
    }

    textInput {
        // 'textInput' is the fallback for all text based controls, such as 'textField', 'textArea',
        // and 'searchField'. Any properties not set here will fall back to those defined in 'control'.
        background {
            width: 200
        }
    }

    // You can define one or more StyleVariations that can be enabled from the
    // application using the attached 'StyleVariation.variations' property.
    // Inside a variation, you list the controls that should receive alternative
    // styling when the variation is active. Any properties defined in a variation
    // override those set in the Style or Theme.
    //
    // For example, if you set "StyleVariation.variations: ['mini']" on a GroupBox
    // in the application, all controls inside that GroupBox will be affected.
    // Exactly which controls are impacted depends on which ones you style inside
    // the variation.
    StyleVariation {
        name: "mini"

        control {
            padding: 2
            background {
                height: 15
            }
            indicator {
                width: 15
                height: 15
            }
            handle {
                width: 15
                height: 15
            }
        }

        textInput {
            background.width: 100
        }

        abstractButton.background {
            width: 60
        }

        switchControl {
            background.width: 40
            indicator.width: 40
            indicator.height: 20
        }

        slider {
            background.width: 100
            indicator.height: 8
        }

        pane {
            padding: 20
            spacing: 5
        }
    }

    /* You can also set one or more StyleVariations on a control type. Unlike Instance
     * variations—which apply only to specific control instances—type variations are applied
     * to *all* instances of a control type without requiring the application to use attached
     * properties.
     *
     * In this example, we specify that all Buttons that are children of a Frame
     * should receive alternative styling, differentiating them from other Buttons. */
    frame {
        background {
            border.width: 1
        }
        variations: StyleVariation {
            button.background {
                radius: 0
                color: palette.accent
                shadow.visible: false
            }
        }
    }
    /* Because 'groupBox' falls back to 'frame', any StyleVariation applied to a frame
     * is automatically inherited by a groupBox as well. Since I in this example only want the
     * different styling on frames, not group boxes, I can simply unset the variation
     * for group boxes. */
    groupBox.variations: []

    readonly property int fancyButton: 0
    CustomControl {
        // You can also define your own custom control types and pair them with custom
        // implementations in your app. Here we provide a base configuration for a control
        // named 'fancyButton', and then override it in the themes to apply colors. Any
        // properties not set here will fall back to those defined in 'control'.
        // The 'controlType' can be any number between 0 and 100000.
        controlType: fancyButton
        background {
            width: 120
            height: 30
            radius: 0
        }
    }

    // A style can have any number of themes. The ones assigned to 'light' and 'dark'
    // will be applied according to the current system theme if 'themeName' is set to
    // "System" (the default). Setting the current themeName for a style is usually done
    // from the application rather than from within the style itself.
    //
    // Within a theme, you can override any properties that should have different values
    // when the theme is applied. Typically, a style configures structural properties
    // such as width, height, padding, and radii, while a theme specifies colors. However,
    // this is not a limitation — any properties can be overridden by a theme. Properties
    // not set in the theme will fall back to those defined in the style.

    light: Theme {
        applicationWindow {
            background.color: "gainsboro"
        }

        control {
            background {
                color: "lightgray"
                border.color: "white"
                shadow.color: "white"
            }

            handle {
                color: "lightgray"
                shadow.color: "white"
                border.color: "white"
            }

            indicator {
                color: "white"
                foreground.image.color: palette.accent
            }

            checked {
                background.shadow.color: "white"
                background.color: "blue"
            }

            focused {
                background.border.color: "white"
                background.shadow.color: "white"
            }

            hovered {
                handle {
                    shadow.color: "white"
                    shadow.scale: 1.6
                    border.color: "lightgray"
                }
            }

            disabled {
                background {
                    opacity: 0.4
                    gradient: null
                }
            }
        }

        abstractButton {
            background {
                shadow.scale: 1.05
            }
            hovered.background {
                color: palette.accent
                border.color: "white"
                shadow.color: "white"
                shadow.scale: 1.4
            }
            checked {
                background.color: palette.accent
            }
        }

        delayButton {
            indicator.color: "transparent"
        }

        comboBox {
            hovered.background {
                color: palette.accent
                border.color: "white"
                shadow.color: "white"
                shadow.scale: 1.4
            }
        }

        itemDelegate {
            padding: 4
            background.height: 40
            hovered.background.color: palette.accent
        }

        menuBarItem {
            hovered.background.color: palette.accent
        }

        menuItem {
            hovered.background.color: palette.accent
        }

        pane {
            background.color: Qt.darker("gainsboro", 1.05)
        }

        textField {
            background {
                shadow.scale: 0
                border.color: "darkgray"
                color: "white"
            }
            hovered.background {
                border.color: "lightgray"
                shadow.scale: 1.1
            }
            focused {
                background.border.color: palette.accent
                background.border.width: 2
            }
            focused.hovered {
                background.border.color: palette.accent
            }
        }

        scrollIndicator {
            indicator.foreground.color: "white"
        }

        StyleVariation {
            name: "alert"
            abstractButton.background {
                color: "orchid"
                border.color: "orchid"
                shadow.color: "orchid"
            }
        }

        CustomControl {
            controlType: fancyButton
            background {
                color: "tan"
            }
        }

        // In a theme, you can also configure the theme palettes. These palettes act as
        // the base palettes for the entire application. The theme palettes in Qt Quick
        // are a combination of colors fetched from the operating system (including the
        // currently active OS theme) and any colors you override in the 'palettes'
        // section below.
        //
        // Because of this, StyleKit styles do not bind colors to the palette by default
        // (except for the accent color). Otherwise, the style’s appearance would vary
        // across platforms, since each platform defines its own palette—unless you
        // explicitly override all palette colors here. If you do want palette-based
        // behavior, you can bind properties to palette colors, e.g.:
        // 'button.text.color: palette.textColor'.

        palettes {
            system.window: "gainsboro"
            textField.text: "#4e4e4e"
            spinBox.highlight: "lightgray"

            button {
                buttonText: "black"
                highlightedText: "black"
                brightText: "#4e4e4e"
                disabled.buttonText: "#4e4e4e"
                disabled.highlightedText: "#4e4e4e"
            }
        }
    }

    dark: Theme {
        applicationWindow {
            background.color: "#544e52"
        }

        control {
            text.color: "lightgray"
            background {
                border.color: "#3d373b"
                shadow.color: "#555555"
                color: "#8e848a"
            }

            handle {
                color: "#8e848a"
                border.color: Qt.darker("#544e52", 1.5)
                shadow.color: "#808080"
            }

            indicator {
                color: Qt.darker("#8e848a", 1.6)
            }

            hovered {
                handle {
                    shadow.color: "white"
                }
            }
        }

        abstractButton {
            checked {
                background.color: palette.accent
            }

            disabled {
                background {
                    opacity: 0.3
                    shadow.color: "transparent"
                }
                checked.background.color: "green"
            }

            focused {
                background {
                    border.color: "white"
                    shadow.color: "white"
                    color: "#bbbbbb"
                }
            }

            hovered {
                background {
                    border.color: "white"
                    color: palette.accent
                    shadow.color: "white"
                    shadow.scale: 1.1
                    shadow.blur: 20
                }
            }
        }

        delayButton {
            indicator.color: "transparent"
        }

        comboBox {
            hovered {
                background {
                    border.color: "white"
                    color: palette.accent
                    shadow.color: "white"
                    shadow.scale: 1.1
                    shadow.blur: 20
                }
            }
        }

        itemDelegate {
            hovered.background.color: palette.accent
        }

        menu {
            background.color: '#433e41'
        }

        menuBar {
            background.color: '#433e41'
        }

        menuBarItem {
            background.color: "#433e41"
            hovered.background.color: palette.accent
        }

        menuSeparator {
            background.color: "#433e41"
        }

        menuItem {
            background.color: "#433e41"
            hovered.background.color: palette.accent
        }

        textInput {
            background.color: "white"
        }

        scrollBar {
            indicator.foreground.color: "white"
        }

        slider {
            indicator.foreground.color: palette.accent
        }

        pane {
            /* The controls change background color on states like hover, but panes
             * should not. Override the property here to disable that behavior for panes. */
            background.color: Qt.lighter("#544e52", 1.3)
            background.border.color: "#3d373b"
        }

        StyleVariation {
            name: "alert"
            abstractButton.background {
                color: "orchid"
                border.color: "orchid"
                shadow.color: "orchid"
            }
        }

        CustomControl {
            controlType: fancyButton
            background {
                color: "thistle"
            }
        }

        palettes {
            system.window: "#544e52"
            textField.text: "black"
            spinBox.highlight: "blue"
            button {
                buttonText: "white"
                highlightedText: "white"
                brightText: "white"
                disabled.buttonText: "darkgray"
                disabled.highlightedText: "darkgray"
            }
        }
    }

    // In addition to 'light' and 'dark', you can define as many themes as you want.
    // You can switch between them from the application, for example using:
    // 'StyleKit.style.themeName: "HighContrast"'.

    CustomTheme {
        name: "HighContrast"
        theme: Theme {
            control {
                transition: null

                background {
                    height: 40
                    shadow.color: "transparent"
                    color: "lightgray"
                    border.color: "black"
                    border.width: 2
                    gradient: null
                }

                indicator {
                    width: 30
                    height: 30
                    color: "ghostwhite"
                    border.color: "black"
                    foreground.margins: 4
                    foreground.color: "black"
                    foreground.image.color: "ghostwhite"
                }

                handle {
                    border.color: "black"
                    border.width: 2
                    width: 30
                    height: 30
                    radius: 30
                    gradient: null
                }

                text.bold: true

                hovered {
                    background.border.width: 4
                    indicator.border.width: 4
                    handle.border.width: 4
                }

                checked {
                    background.border.width: 6
                }

                disabled {
                    background.color: "white"
                }
            }

            abstractButton {
                background.color: "ghostwhite"
            }

            delayButton {
                indicator {
                    color: "transparent"
                    foreground.margins: 0
                }
                checked.text.color: "white"
            }

            dial {
                handle.width: 15
                handle.height: 15
                indicator {
                    width: 60
                    height: 60
                    foreground.margins: 0
                }
            }

            textInput {
                background.color: "white"
            }

            slider {
                indicator {
                    width: 180
                    height: 12
                    color: "ghostwhite"
                    border.width: 1
                    foreground.color: "black"
                }
                vertical {
                    background {
                        width: 12
                        height: 180
                    }
                    indicator {
                        width: 12
                        height: 180
                    }
                }
            }

            radioButton {
                indicator.radius: 255
                indicator.foreground.radius: 255
            }

            switchControl {
                background {
                    color: "ghostwhite"
                    border.width: 2
                }

                indicator {
                    radius: 16
                    margins: 0
                    border.width: 2
                    width: 60
                    height: 40
                    foreground.color: "transparent"
                }

                handle {
                    width: 20
                    height: 30
                    border.width: 2
                    color: "white"
                    margins: 6
                    radius: 0
                    topLeftRadius: 18
                    bottomLeftRadius: 18
                }

                hovered {
                    indicator.border.width: 4
                }

                checked {
                    handle {
                        color: "black"
                        radius: 0
                        topRightRadius: 18
                        bottomRightRadius: 18
                    }
                }
            }

            spinBox {
                indicator.color: "black"
                indicator.foreground.image.color: "white"
                hovered.background.border.width: 6
            }

            itemDelegate {
                background.border.width: 0
                hovered.background.border.width: 2
                hovered.text.bold: true
            }

            scrollBar {
                background.width: 15
                background.height: 15
                indicator.width: 15
                indicator.height: 15
                indicator.border.width: 3
                indicator.foreground.margins: 3
                indicator.foreground.color: "lightgray"
            }

            menu {
                background.color: "black"
            }

            menuBar {
                background.color: "black"
            }

            menuBarItem {
                text.color: "white"
                background.color: "black"
                hovered.background.color: "white"
                hovered.text.color: "black"
            }

            menuSeparator {
                background.color: "black"
                background.height: 1
                indicator.height: 1
                indicator.border.width: 0
            }

            menuItem {
                text.color: "white"
                text.padding: 6
                background.color: "black"
                hovered.background.color: "white"
                hovered.text.color: "black"
            }

            palettes {
                system.window: "white"
                textField.text: "black"
                button {
                    buttonText: "black"
                    highlightedText: "black"
                    brightText: "black"
                    disabled.buttonText: "white"
                    disabled.highlightedText: "white"
                }
            }
        }
    }

    CustomTheme {
        name: "Green"
        theme: Theme {
            applicationWindow {
                background.color: "#8da28d"
            }

            control {
                background {
                    border.color: "#547454"
                    shadow.color: "darkseagreen"
                    color: "#a0c0a0"
                }

                handle {
                    border.color: "#547454"
                    shadow.color: "darkseagreen"
                    color: "#a0c0a0"
                }

                indicator {
                    color: "white"
                    border.color: "#547454"
                    foreground.color: "white"
                }

                text {
                    color: "#1c261c"
                    bold: true
                }

                hovered {
                    background {
                        color: "#ecefec"
                        border.color: "#ecefec"
                        shadow.color: "white"
                    }
                    handle {
                        color: "#ecefec"
                        border.color: "#ecefec"
                        shadow.color: "white"
                    }
                }

                checked {
                    indicator {
                        foreground.color: "#678367"
                        foreground.image.color: "#678367"
                    }
                }

                disabled {
                    background {
                        color: "#80a080"
                        shadow.color: "transparent"
                    }
                }
            }

            checkBox {
                indicator.foreground.color: "transparent"
            }

            comboBox {
                indicator.color: "transparent"
                indicator.foreground.color: "transparent"
                indicator.foreground.image.color: "white"
            }

            delayButton {
                indicator.color: "transparent"
            }

            pane {
                background.color: "#a0b1a0"
                background.border.color: "#415a41"
            }

            scrollIndicator {
                indicator.foreground.color: "white"
            }

            spinBox {
                indicator.color: "transparent"
                indicator.foreground.color: "transparent"
                indicator.foreground.image.color: "white"
            }

            switchControl {
                indicator.foreground.color: "white"
                checked.indicator.foreground.color: "#678367"
            }

            textInput {
                background.color: "white"
            }

            menuBar {
                background.color: "#8da28d"
            }

            menuBarItem {
                background.color: "#8da28d"
                hovered.background.color: "white"
            }

            menuSeparator {
                background.color: "#a0c0a0"
            }

            StyleVariation {
                name: "alert"
                abstractButton.background {
                    color: "lime"
                    border.color: "lime"
                    shadow.color: "lime"
                }
            }

            palettes {
                system.window: "#547454"
                textField.text: "green"
                textField.placeholderText: "#678367"
                checkBox.buttonText: "white"
                button {
                    buttonText: "black"
                    highlightedText: "white"
                    disabled.buttonText: "lightgray"
                    disabled.highlightedText: "lightgray"
                }
            }
        }
    }

    CustomTheme {
        name: "Empty Theme"
        theme: Theme {}
    }
}
import QtQuick
import Qt.labs.StyleKit

Style {
    control {
        // We start by styling a control in its 'normal' state
        leftPadding: 20
        rightPadding: 20

        background {
            border.color: palette.accent
            radius: 4
        }

        handle {
            color: palette.accent.lighter(1.2)
        }

        hovered {
            // Here we override some of the properties for the 'hovered' state. The ones
            // we don't set here will fall back to be read from the 'normal' state.
            handle.color: palette.accent.darker(1.2)
        }

        hovered.pressed {
            // The states can also be nested. Since 'hovered.pressed' is more specific
            // than 'hovered', the former will be read first if the same property is set
            // in multiple states.
            background {
                color: palette.accent.darker(1.2)
                scale: 0.95
            }
        }

        checked {
            text.color: "white"
            background {
                color: palette.accent.darker(1.2)
                scale: 0.95
            }
        }

        checked.hovered {
            background.color: palette.accent
        }

        checked.hovered.pressed {
            background.color: palette.accent.darker(1.2)
        }

        transition: Transition {
           ColorAnimation {
                properties: "background.color"
                duration: 100
           }
        }
    }

    abstractButton {
        // After styling what is common to all the controls in the 'control' section
        // above, we now override and set properties that should be specific to only
        // some of the controls.
        // In this style, we want to show the background for all button types, such as
        // 'button', 'checkBox', 'radioButton', etc, so we set 'background.visible: true'.
        // By default, the background is normally hidden for most controls.
        background {
            visible: true
            shadow {
                color: "darkgray"
                horizontalOffset: 2
                verticalOffset: 2
            }
        }
        hovered.background.color: palette.accent
    }

    delayButton {
        padding: 0
        indicator {
            radius: 4
            foreground {
                radius: 4
                color: palette.accent.lighter(1.2)
            }
        }
        checked.indicator.foreground.color: palette.accent.darker(1.2)
    }

    itemDelegate {
        // We don't want the menu items in a ComboBox to fade, so we override and unset
        // the transition previously set for all controls in the 'control' section.
        transition: null
        background.radius: 0
        background.color: Qt.alpha(palette.accent, 0)
        hovered {
            background.color: palette.accent
            text.color: "white"
        }
    }

    menuBar {
        padding: 0
    }

    menuBarItem {
        background.color: Qt.alpha(palette.accent, 0)
        hovered.background.color: palette.accent
    }

    menu {
        padding: 2
    }

    menuItem {
        background.color: Qt.alpha(palette.accent, 0)
        hovered.background.color: palette.accent
    }

    menuSeparator {
        indicator.color: palette.accent
    }

    popup {
        // Remove padding so that item delegates span the full width
        padding: 0
    }

    roundButton {
        background.radius: 255
    }

    scrollBar {
        // Hide the background, showing only the groove and handle
        background.visible: false
        padding: 0
    }

    scrollIndicator {
        padding: 2
    }

    pane {
        /* The controls change background color on states like hover, but panes
         * should not. Override the property here to disable that behavior for panes. */
        background.color: "white"
    }

    applicationWindow {
        background.color: "whitesmoke"
    }
}
import QtQuick
import Qt.labs.StyleKit

Style {
    id: style

    component ColorSet : QtObject {
        property color normal
        property color muted
        property color subtle
    }

    property MyTheme myTheme: theme as MyTheme

    component MyTheme : Theme {
        property ColorSet neutralBackground
        property ColorSet neutralStroke
        property ColorSet neutralForeground
        property ColorSet accentBackground
        property ColorSet accentStroke
        property ColorSet accentForeground // on-accent

        property real controlHeight: 50
        property color windowColor: "#f7f7f7"
        property color shadowColor: "#404040"

        palettes {
            system.window: windowColor
            textField {
                text: neutralForeground.normal
                disabled.text: neutralForeground.muted
            }

            checkBox.buttonText: neutralForeground.normal
            button {
                buttonText: neutralForeground.normal
                highlightedText: neutralForeground.normal
                brightText: neutralForeground.normal //????
                disabled.buttonText: neutralForeground.subtle
                disabled.highlightedText: neutralForeground.subtle
            }
        }
    }

    Gradient {
        id: faintHorizontalGradient
        orientation: Gradient.Horizontal
        GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
        GradientStop { position: 1.0; color: Qt.alpha("black", 0.1)}
    }

    Gradient {
        id: faintVerticalGradient
        orientation: Gradient.Vertical
        GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
        GradientStop { position: 1.0; color: Qt.alpha("black", 0.1)}
    }

    Gradient {
        id: strongHorizontalGradient
        orientation: Gradient.Horizontal
        GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
        GradientStop { position: 1.0; color: Qt.alpha("black", 0.4)}
    }

    Gradient {
        id: strongVerticalGradient
        orientation: Gradient.Vertical
        GradientStop { position: 0.0; color: Qt.alpha("black", 0.0)}
        GradientStop { position: 1.0; color: Qt.alpha("black", 0.4)}
    }

    applicationWindow {
        background.color: myTheme.windowColor
    }

    control {
        leftPadding: 10
        topPadding: 5
        rightPadding: 10
        bottomPadding: 5

        background {
            height: myTheme.controlHeight
            color: myTheme.neutralBackground.normal
        }

        vertical {
            background.gradient: faintHorizontalGradient
            indicator.gradient: faintHorizontalGradient
        }

        handle {
            width: 36
            height: 36
            radius: 18
            border.width: 2
            border.color: myTheme.neutralStroke.normal
            color: myTheme.accentForeground.normal
        }

        indicator {
            height: myTheme.controlHeight
            radius: 25
            border.width: 3
            border.color: myTheme.neutralStroke.normal
            color: myTheme.neutralBackground.normal
            foreground {
                radius: 25
                gradient: strongVerticalGradient
                border.width: 3
                border.color: myTheme.accentStroke.normal
                color: myTheme.accentBackground.normal
            }
        }

        hovered {
            handle.border.width: 5
        }
    }

    abstractButton {
        background {
            width: 100
            radius: 255
            border.width: 2
            border.color: myTheme.neutralStroke.normal
            color: myTheme.neutralBackground.normal
            gradient: faintVerticalGradient

            shadow {
                opacity: 0.25
                scale: 1.05
                verticalOffset: 2.5
                horizontalOffset: 2
                color: myTheme.shadowColor
                blur: 5
            }
        }

        hovered {
            background.color: myTheme.neutralBackground.muted
            checked.background.color: myTheme.accentBackground.muted
        }

        pressed {
            background.scale: 0.95
        }

        checked {
            background {
                color: myTheme.accentBackground.normal
                border.color: myTheme.accentStroke.normal
            }
        }

        disabled {
            background {
                color: myTheme.neutralBackground.subtle
                border.color: myTheme.neutralStroke.subtle
                shadow.color: "transparent"
            }
        }
    }

    delayButton {
        padding: 0
        indicator {
            color: "transparent"
            border.width: 0
        }
    }

    pane {
        padding: 20
        background.delegate: null
    }

    scrollIndicator {
        padding: 2
        background.height: 6
        indicator.height: 6
        vertical {
            background.width: 6
            indicator.width: 6
        }
    }

    scrollBar {
        padding: 2
        background.height: 20
        background.visible: false
        indicator.height: 20
        vertical {
            background.width: 20
            indicator.width: 20
        }
    }

    checkBox {
        indicator {
            width: 35
            height: 35
            radius: 4
            border.width: 1.5
            foreground {
                radius: 4
                border.width: 1.5
                image.color: myTheme.accentForeground.normal
                color: myTheme.accentBackground.normal
            }
        }
    }

    dial {
        indicator {
            width: 184
            height: 184
            radius: 255
            foreground {
                width: 8
                height: 8
            }
        }
    }

    radioButton {
        indicator {
            width: 35
            height: 35
            radius: width / 2
            border.width: 1.5
            foreground {
                margins: 4
                radius: width / 2
                border.width: 0
                //image.color: myTheme.activeHighlight
                color: myTheme.accentBackground.normal
                gradient: faintVerticalGradient
            }
        }
        checked {
            indicator.border.color: myTheme.accentStroke.normal
        }
    }

    roundButton {
        background.radius: 255
    }

    popup {
        padding: 2
        topPadding: 10
        bottomPadding: 10
    }

    comboBox {
        background {
            width: 200
            height: myTheme.controlHeight
            radius: myTheme.controlHeight / 2
            border.color: myTheme.neutralStroke.normal
            color: myTheme.neutralBackground.normal
        }
        indicator {
            height: myTheme.controlHeight / 6
            color: "transparent"
            border.width: 0
            foreground {
                margins: 4
                color: "transparent"
                border.width: 0
                gradient: null
                image.color: myTheme.neutralStroke.subtle
            }
        }
    }

    spinBox {
        background {
            radius: myTheme.controlHeight / 2
        }
        indicator {
            radius: 0
            color: "transparent"
            border.width: 0
            foreground.gradient: null
            foreground.color: "transparent"
            foreground.image.color: myTheme.accentStroke.normal
            foreground.border.width: 0
            foreground.width: 20
            foreground.height: 20
        }
    }

    textField {
        background {
            radius: 9999999999
            width: 200
            height: myTheme.controlHeight
            border.color: myTheme.neutralStroke.normal
            color: myTheme.neutralBackground.normal
        }
        hovered.background.color: myTheme.neutralBackground.muted
        focused.background.border.color: myTheme.accentStroke.normal
    }

    slider {
        spacing: 26
        background.width: 180
        indicator.foreground.minimumWidth: 50
        indicator.foreground.margins: 2
        handle {
            leftMargin: 8
            rightMargin: 8
        }
        vertical {
            background {
                height: 180
                width: myTheme.controlHeight
            }
            indicator {
                width: myTheme.controlHeight
                foreground.minimumWidth: 0
                foreground.minimumHeight: 50
            }
            handle {
                leftMargin: 0
                rightMargin: 0
                topMargin: 8
                bottomMargin: 8
            }
        }
    }

    switchControl {
        spacing: 8
        indicator {
            width: 80
            height: myTheme.controlHeight
            foreground.visible: false
        }
        handle {
            leftMargin: 8
            rightMargin: 8
        }
        checked {
            indicator {
                color: myTheme.accentBackground.normal
                border.color: myTheme.accentStroke.normal
                gradient: strongVerticalGradient
            }
        }
    }

    flatButton {
        hovered.background.visible: true
        checked.background.visible: true
        hovered.background.color: myTheme.neutralBackground.muted
        checked.background.color: myTheme.accentBackground.normal
        hovered.checked.background.color: myTheme.accentBackground.muted
    }

    itemDelegate {
        hovered.background.color: myTheme.accentBackground.normal
    }

    menu {
        padding: 2
        topPadding: 10
        bottomPadding: 10
        background.width: 100
    }

    menuBar {
        padding: 2
        background.height: 30
    }

    menuBarItem {
        padding: 2
        background.width: 100
        background.height: 30
        hovered.background.color: myTheme.accentBackground.normal
    }

    menuItem {
        padding: 2
        text.padding: 4
        background.height: 30
        indicator.height: 30
        hovered.background.color: myTheme.accentBackground.normal
    }

    menuSeparator {
        padding: 4

        background {
            width: 100
            height: 0
            color: "transparent"
            border.width: 0
        }

        indicator {
            height: 1
            width: 100
            color: myTheme.neutralStroke.normal
            border.width: 0

            foreground.margins: 0
            foreground.visible: false
        }
    }

    // THEMES

    light: MyTheme {
        windowColor: "#EFF5F5F5" // #F5F5F5 · 92% #EF
        shadowColor: "#AEAEAE"

        accentBackground: ColorSet {
            normal: "#8671EC"
            muted: "#B7ABF4"
            subtle: "#D9D2F9"
        }
        accentStroke: ColorSet {
            normal: "#4530B0"
            muted: "#654FD4"
            subtle: "#8671EC"
        }
        accentForeground: ColorSet {
            normal: "#FFFFFF"
            muted: "#909090"
            subtle: "#B7ABF4"
        }

        neutralBackground:  ColorSet {
            normal: "#FFFFFF" //#FFFFFF · 78% #C7
            muted: "#FCFCFC" //#FCFCFC · 92% #EF
            subtle: "#E3E3E3" //#E3E3E3 · 94% #F0
        }
        neutralStroke: ColorSet {
            normal: "#CDCDCD"
            muted: "#AEAEAE"
            subtle: "#BEBEBE"
        }
        neutralForeground: ColorSet {
            normal: "#000000"
            muted: "#2D2D2D"
            subtle: "#A9A9A9"
        }
    }

    dark: MyTheme {
        windowColor: "#EF444444" // #222222 · 92% #EF
        shadowColor: "#000"

        accentBackground: ColorSet {
            normal: "#654FD4"
            muted: "#4530B0"
            subtle: "#361EAB"
        }
        accentStroke: ColorSet {
            normal: "#654FD4"
            muted: "#654FD4"
            subtle: "#8671EC"
        }
        accentForeground: ColorSet {
            normal: "#E0E0E0"
            muted: "#A9A9A9"
            subtle: "#654FD4"
        }

        neutralBackground:  ColorSet {
            normal: "#434343" //#434343 · 78% #C7
            muted: "#636363" // #636363 · 92% #EF
            subtle: "#545454" //#545454 · 94% #F0
        }
        neutralStroke: ColorSet {
            normal: "#A9A9A9"
            muted: "#545454"
            subtle: "#3B3B3B"
        }
        neutralForeground: ColorSet {
            normal: "#FFFFFF"
            muted: "#BEBEBE"
            subtle: "#353535"
        }
    }

    CustomTheme {
        name: "Green"
        theme: MyTheme {
                windowColor: "#f0f4fbf4"

            accentBackground: ColorSet {
                normal: "green"
                muted: Qt.lighter("green")
                subtle: Qt.lighter("green", 2)
            }
            accentStroke: ColorSet {
                normal: "darkgreen"
                muted: Qt.lighter("darkgreen")
                subtle: Qt.lighter("darkgreen", 2)
            }
            accentForeground: ColorSet {
                normal: "#FFFFFF"
                muted: "#909090"
                subtle: "#B7ABF4"
            }

            neutralBackground:  ColorSet {
                normal: "#C7EEFFEE"
                muted: "#EFF0FCF0"
                subtle: "#F0E0F0E0"
            }
            neutralStroke: ColorSet {
                normal: "#CDDDCD"
                muted: "#AEBEAE"
                subtle: "#BECEBE"
            }
            neutralForeground: ColorSet {
                normal: "#000000"
                muted: "#2D2D2D"
                subtle: "#A9A9A9"
            }
        }
    }
}