qmldir

module App

qtquickcontrols2.conf

[Material]
Primary=#41cd52
Accent=#41cd52
Theme=System

[Universal]
Accent=#41cd52
Theme=System

ToolBar.qml

import QtQuick.Controls

ToolBar {}

+Material/ToolBar.qml

import QtQuick.Controls.Material

ToolBar {
    Material.foreground: "white"
}

pages/ComboBoxPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "ComboBox is a combined button and popup list. It presents "
                + "a list of options to the user that occupies minimal screen space."
        }

        ComboBox {
            model: ["First", "Second", "Third"]
            anchors.horizontalCenter: parent.horizontalCenter
        }

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "ComboBox can be made \l editable. An editable combo box auto-"
                + "completes its text based on what is available in the model."
        }

        ComboBox {
            editable: true
            model: ListModel {
                id: model
                ListElement { text: "Banana" }
                ListElement { text: "Apple" }
                ListElement { text: "Coconut" }
            }
            onAccepted: {
                if (find(editText) === -1)
                    model.append({text: editText})
            }
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/FramePage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    readonly property int itemWidth: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 3, page.availableWidth / 3 * 2))

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "Frame is used to layout a logical group of controls together, within a visual frame."
        }

        Frame {
            anchors.horizontalCenter: parent.horizontalCenter

            Column {
                spacing: 20
                width: page.itemWidth

                RadioButton {
                    text: "First"
                    checked: true
                    width: parent.width
                }
                RadioButton {
                    id: button
                    text: "Second"
                    width: parent.width
                }
                RadioButton {
                    text: "Third"
                    width: parent.width
                }
            }
        }
    }
}

pages/SliderPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "Slider is used to select a value by sliding a handle along a track."
        }

        Slider {
            id: slider
            value: 0.5
            anchors.horizontalCenter: parent.horizontalCenter
        }

        Slider {
            orientation: Qt.Vertical
            value: 0.5
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/TumblerPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "Tumbler is used to select a value by spinning a wheel."
        }

        Tumbler {
            model: 10
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/SpinBoxPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "SpinBox allows the user to choose an integer value by clicking the up or down indicator buttons, "
                + "by pressing up or down on the keyboard, or by entering a text value in the input field."
        }

        SpinBox {
            id: box
            value: 50
            anchors.horizontalCenter: parent.horizontalCenter
            editable: true
        }
    }
}

pages/ProgressBarPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "ProgressBar indicates the progress of an operation. It can be set in an "
                + "indeterminate mode to indicate that the length of the operation is unknown."
        }

        ProgressBar {
            id: bar
            value: 0.5
            anchors.horizontalCenter: parent.horizontalCenter
        }

        ProgressBar {
            indeterminate: true
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/DelegatePage.qml

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls

Pane {
    padding: 0

    property var delegateComponentMap: {
        "ItemDelegate": itemDelegateComponent,
        "SwipeDelegate": swipeDelegateComponent,
        "CheckDelegate": checkDelegateComponent,
        "RadioDelegate": radioDelegateComponent,
        "SwitchDelegate": switchDelegateComponent
    }

    Component {
        id: itemDelegateComponent

        ItemDelegate {
            text: labelText
            width: parent.width
        }
    }

    Component {
        id: swipeDelegateComponent

        SwipeDelegate {
            id: swipeDelegate
            text: labelText
            width: parent.width

            Component {
                id: removeComponent

                Rectangle {
                    color: SwipeDelegate.pressed ? "#333" : "#444"
                    width: parent.width
                    height: parent.height
                    clip: true

                    SwipeDelegate.onClicked: view.model.remove(ourIndex)

                    Label {
                        font.pixelSize: swipeDelegate.font.pixelSize
                        text: "Remove"
                        color: "white"
                        anchors.centerIn: parent
                    }
                }
            }

            swipe.left: removeComponent
            swipe.right: removeComponent
        }
    }

    Component {
        id: checkDelegateComponent

        CheckDelegate {
            text: labelText
        }
    }

    ButtonGroup {
        id: radioButtonGroup
    }

    Component {
        id: radioDelegateComponent

        RadioDelegate {
            text: labelText
            ButtonGroup.group: radioButtonGroup
        }
    }

    Component {
        id: switchDelegateComponent

        SwitchDelegate {
            text: labelText
        }
    }

    ColumnLayout {
        id: column
        spacing: 40
        anchors.fill: parent
        anchors.topMargin: 20

        Label {
            Layout.fillWidth: true
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "Delegate controls are used as delegates in views such as ListView."
        }

        ListView {
            id: listView
            Layout.fillWidth: true
            Layout.fillHeight: true
            clip: true
            model: ListModel {
                ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
                ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
                ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
            }

            section.property: "type"
            section.delegate: Pane {
                width: listView.width
                height: sectionLabel.implicitHeight + 20

                Label {
                    id: sectionLabel
                    text: section
                    anchors.centerIn: parent
                }
            }

            delegate: Loader {
                id: delegateLoader
                width: listView.width
                sourceComponent: delegateComponentMap[text]

                property string labelText: text
                property ListView view: listView
                property int ourIndex: index

                // Can't find a way to do this in the SwipeDelegate component itself,
                // so do it here instead.
                ListView.onRemove: SequentialAnimation {
                    PropertyAction {
                        target: delegateLoader
                        property: "ListView.delayRemove"
                        value: true
                    }
                    NumberAnimation {
                        target: item
                        property: "height"
                        to: 0
                        easing.type: Easing.InOutQuad
                    }
                    PropertyAction {
                        target: delegateLoader
                        property: "ListView.delayRemove"
                        value: false
                    }
                }
            }
        }
    }
}

pages/StackViewPage.qml

import QtQuick
import QtQuick.Controls

StackView {
    id: stackView
    initialItem: page

    Component {
        id: page

        Pane {
            id: pane
            width: parent ? parent.width : 0 // TODO: fix null parent on destruction

            Column {
                spacing: 40
                width: parent.width

                Label {
                    width: parent.width
                    wrapMode: Label.Wrap
                    horizontalAlignment: Qt.AlignHCenter
                    text: "StackView provides a stack-based navigation model which can be used with a set of interlinked pages. "
                    + "Items are pushed onto the stack as the user navigates deeper into the material, and popped off again "
                    + "when he chooses to go back."
                }

                Button {
                    id: button
                    text: "Push"
                    anchors.horizontalCenter: parent.horizontalCenter
                    width: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 2, pane.availableWidth / 3))
                    onClicked: stackView.push(page)
                }

                Button {
                    text: "Pop"
                    enabled: stackView.depth > 1
                    width: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 2, pane.availableWidth / 3))
                    anchors.horizontalCenter: parent.horizontalCenter
                    onClicked: stackView.pop()
                }
            }
        }
    }
}

pages/DialPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "The Dial is similar to a traditional dial knob that is found on devices such as "
                + "stereos or industrial equipment. It allows the user to specify a value within a range."
        }

        Dial {
            value: 0.5
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/PageIndicatorPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "PageIndicator is used to indicate the currently active page in a container of pages."
        }

        PageIndicator {
            count: 5
            currentIndex: 2
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/SwipeViewPage.qml

import QtQuick
import QtQuick.Controls

Pane {
    id: pane

    SwipeView {
        id: view
        currentIndex: 1
        anchors.fill: parent

        Repeater {
            model: 3

            Pane {
                width: view.width
                height: view.height

                Column {
                    spacing: 40
                    width: parent.width

                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "SwipeView provides a navigation model that simplifies horizontal paged scrolling. "
                        + "The page indicator on the bottom shows which is the presently active page."
                    }

                    Image {
                        source: "../images/arrows.png"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    }

    PageIndicator {
        count: view.count
        currentIndex: view.currentIndex
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
    }
}

pages/TabBarPage.qml

import QtQuick
import QtQuick.Controls

Page {
    id: page

    SwipeView {
        id: swipeView
        anchors.fill: parent
        currentIndex: tabBar.currentIndex

        Repeater {
            model: 3

            Pane {
                width: swipeView.width
                height: swipeView.height

                Column {
                    spacing: 40
                    width: parent.width

                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "TabBar is a bar with icons or text which allows the user "
                              + "to switch between different subtasks, views, or modes."
                    }

                    Image {
                        source: "../images/arrows.png"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    }

    footer: TabBar {
        id: tabBar
        currentIndex: swipeView.currentIndex

        TabButton {
            text: "First"
        }
        TabButton {
            text: "Second"
        }
        TabButton {
            text: "Third"
        }
    }
}

pages/TextFieldPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "TextField is a single-line text editor."
        }

        TextField {
            id: field
            placeholderText: "TextField"
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}

pages/GroupBoxPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    readonly property int itemWidth: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 3, page.availableWidth / 3 * 2))

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "A GroupBox provides a frame, a title on top of it, and a logical group of controls within that frame."
        }

        GroupBox {
            title: "Title"
            anchors.horizontalCenter: parent.horizontalCenter

            Column {
                spacing: 20
                width: page.itemWidth

                RadioButton {
                    text: "First"
                    checked: true
                    width: parent.width
                }
                RadioButton {
                    id: button
                    text: "Second"
                    width: parent.width
                }
                RadioButton {
                    text: "Third"
                    width: parent.width
                }
            }
        }
    }
}

pages/RadioButtonPage.qml

import QtQuick
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "RadioButton presents an option button that can be toggled on or off. "
                + "Radio buttons are typically used to select one option from a set of options."
        }

        Column {
            spacing: 20
            anchors.horizontalCenter: parent.horizontalCenter

            RadioButton {
                text: "First"
            }
            RadioButton {
                text: "Second"
                checked: true
            }
            RadioButton {
                text: "Third"
                enabled: false
            }
        }
    }
}

pages/ButtonPage.qml

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls

ScrollablePage {
    id: page

    Column {
        spacing: 40
        width: parent.width

        Label {
            width: parent.width
            wrapMode: Label.Wrap
            horizontalAlignment: Qt.AlignHCenter
            text: "Button presents a push-button that can be pushed or clicked by the user. "
                + "Buttons are normally used to perform an action, or to answer a question."
        }

        ColumnLayout {
            spacing: 20
            anchors.horizontalCenter: parent.horizontalCenter

            Button {
                text: "First"
                Layout.fillWidth: true
            }
            Button {
                id: button
                text: "Second"
                highlighted: true
                Layout.fillWidth: true
            }
            Button {
                text: "Third"
                enabled: false
                Layout.fillWidth: true
            }
        }
    }
}

pages/ScrollIndicatorPage.qml

import QtQuick
import QtQuick.Controls

Flickable {
    id: flickable

    contentHeight: pane.height

    Pane {
        id: pane
        width: flickable.width
        height: flickable.height * 1.25

        Column {
            id: column
            spacing: 40
            width: parent.width

            Label {
                width: parent.width
                wrapMode: Label.Wrap
                horizontalAlignment: Qt.AlignHCenter
                text: "ScrollIndicator is a non-interactive indicator that indicates the current scroll position. "
                    + "A scroll indicator can be either vertical or horizontal, and can be attached to any Flickable, "