- Qt 5.5
- Qt Quick Extras
- Qt Quick Extras - Gallery
- gallery.qml Example File
- Qt 5.5.1 Reference Documentation

# gallery.qml Example File

gallery/qml/gallery.qml

    /****************************************************************************
    **
    ** Copyright (C) 2015 The Qt Company Ltd.
    ** Contact: http://www.qt.io/licensing/
    **
    ** This file is part of the examples of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** You may use this file under the terms of the BSD license as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of The Qt Company Ltd nor the names of its
    **     contributors may be used to endorse or promote products derived
    **     from this software without specific prior written permission.
    **
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/

    import QtQuick 2.2
    import QtGraphicalEffects 1.0
    import QtQuick.Controls 1.4
    import QtQuick.Controls.Styles 1.4
    import QtQuick.Dialogs 1.0
    import QtQuick.Extras 1.4
    import QtQuick.Layouts 1.0
    import QtQuick.Window 2.1

    Window {
        id: root
        objectName: "window"
        visible: true
        width: 480
        height: 800

        color: "#161616"
        title: "Qt Quick Extras Demo"

        function toPixels(percentage) {
            return percentage * Math.min(root.width, root.height);
        }

        property bool isScreenPortrait: height > width
        property color lightFontColor: "#222"
        property color darkFontColor: "#e7e7e7"
        readonly property color lightBackgroundColor: "#cccccc"
        readonly property color darkBackgroundColor: "#161616"
        property real customizerPropertySpacing: 10
        property real colorPickerRowSpacing: 8

        Text {
            id: textSingleton
        }

        property Component circularGauge: CircularGaugeView {}

        property Component dial: ControlView {
            darkBackground: false

            control: Column {
                id: dialColumn
                width: controlBounds.width
                height: controlBounds.height - spacing
                spacing: root.toPixels(0.05)

                ColumnLayout {
                    id: volumeColumn
                    width: parent.width
                    height: (dialColumn.height - dialColumn.spacing) / 2
                    spacing: height * 0.025

                    Dial {
                        id: volumeDial
                        anchors.horizontalCenter: parent.horizontalCenter
                        Layout.fillWidth: true
                        Layout.fillHeight: true

                        /*!
                            Determines whether the dial animates its rotation to the new value when
                            a single click or touch is received on the dial.
                        */
                        property bool animate: customizerItem.animate

                        Behavior on value {
                            enabled: volumeDial.animate && !volumeDial.pressed
                            NumberAnimation {
                                duration: 300
                                easing.type: Easing.OutSine
                            }
                        }
                    }

                    ControlLabel {
                        id: volumeText
                        text: "Volume"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }

                ColumnLayout {
                    id: trebleColumn
                    width: parent.width
                    height: (dialColumn.height - dialColumn.spacing) / 2
                    spacing: height * 0.025

                    Dial {
                        id: dial2
                        anchors.horizontalCenter: parent.horizontalCenter
                        Layout.fillWidth: true
                        Layout.fillHeight: true

                        stepSize: 1
                        maximumValue: 10

                        style: DialStyle {
                            labelInset: outerRadius * 0
                        }
                    }

                    ControlLabel {
                        id: trebleText
                        text: "Treble"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }

            customizer: Column {
                spacing: customizerPropertySpacing

                property alias animate: animateCheckBox.checked

                CustomizerLabel {
                    text: "Animate"
                }

                CustomizerSwitch {
                    id: animateCheckBox
                }
            }
        }

        property Component delayButton: ControlView {
            darkBackground: false

            control: DelayButton {
                text: "Alarm"
                anchors.centerIn: parent
            }
        }

        property Component gauge: ControlView {
            id: gaugeView
            control: Gauge {
                id: gauge
                width: orientation === Qt.Vertical ? implicitWidth : gaugeView.controlBounds.width
                height: orientation === Qt.Vertical ? gaugeView.controlBounds.height : implicitHeight
                anchors.centerIn: parent

                minimumValue: 0
                value: customizerItem.value
                maximumValue: 100
                orientation: customizerItem.orientationFlag ? Qt.Vertical : Qt.Horizontal
                tickmarkAlignment: orientation === Qt.Vertical
                    ? (customizerItem.alignFlag ? Qt.AlignLeft : Qt.AlignRight)
                    : (customizerItem.alignFlag ? Qt.AlignTop : Qt.AlignBottom)
            }

            customizer: Column {
                spacing: customizerPropertySpacing

                property alias value: valueSlider.value
                property alias orientationFlag: orientationCheckBox.checked
                property alias alignFlag: alignCheckBox.checked

                CustomizerLabel {
                    text: "Value"
                }

                CustomizerSlider {
                    id: valueSlider
                    minimumValue: 0
                    value: 50
                    maximumValue: 100
                }

                CustomizerLabel {
                    text: "Vertical orientation"
                }

                CustomizerSwitch {
                    id: orientationCheckBox
                    checked: true
                }

                CustomizerLabel {
                    text: controlItem.orientation === Qt.Vertical ? "Left align" : "Top align"
                }

                CustomizerSwitch {
                    id: alignCheckBox
                    checked: true
                }
            }
        }

        property Component toggleButton: ControlView {
            darkBackground: false

            control: ToggleButton {
                text: checked ? "On" : "Off"
                anchors.centerIn: parent
            }
        }

        property Component pieMenu: PieMenuControlView {}

        property Component statusIndicator: ControlView {
            id: statusIndicatorView
            darkBackground: false

            Timer {
                id: recordingFlashTimer
                running: true
                repeat: true
                interval: 1000
            }

            ColumnLayout {
                id: indicatorLayout
                width: statusIndicatorView.controlBounds.width * 0.25
                height: statusIndicatorView.controlBounds.height * 0.75
                anchors.centerIn: parent

                Repeater {
                    model: ListModel {
                        id: indicatorModel
                        ListElement {
                            name: "Power"
                            indicatorColor: "#35e02f"
                        }
                        ListElement {
                            name: "Recording"
                            indicatorColor: "red"
                        }
                    }

                    ColumnLayout {
                        Layout.preferredWidth: indicatorLayout.width
                        spacing: 0

                        StatusIndicator {
                            id: indicator
                            color: indicatorColor
                            Layout.preferredWidth: statusIndicatorView.controlBounds.width * 0.07
                            Layout.preferredHeight: Layout.preferredWidth
                            Layout.alignment: Qt.AlignHCenter
                            on: true

                            Connections {
                                target: recordingFlashTimer
                                onTriggered: if (name == "Recording") indicator.active = !indicator.active
                            }
                        }
                        ControlLabel {
                            id: indicatorLabel
                            text: name
                            Layout.alignment: Qt.AlignHCenter
                            Layout.maximumWidth: parent.width
                            horizontalAlignment: Text.AlignHCenter
                        }
                    }
                }
            }
        }

        property Component tumbler: ControlView {
            id: tumblerView
            darkBackground: false

            Tumbler {
                id: tumbler
                anchors.centerIn: parent

                // TODO: Use FontMetrics with 5.4
                Label {
                    id: characterMetrics
                    font.bold: true
                    font.pixelSize: textSingleton.font.pixelSize * 1.25
                    font.family: openSans.name
                    visible: false
                    text: "M"
                }

                readonly property real delegateTextMargins: characterMetrics.width * 1.5
                readonly property var days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

                TumblerColumn {
                    id: tumblerDayColumn

                    function updateModel() {
                        var previousIndex = tumblerDayColumn.currentIndex;
                        var newDays = tumbler.days[monthColumn.currentIndex];

                        if (!model) {
                            var array = [];
                            for (var i = 0; i < newDays; ++i) {
                                array.push(i + 1);
                            }
                            model = array;
                        } else {
                            // If we've already got days in the model, just add or remove
                            // the minimum amount necessary to make spinning the month column fast.
                            var difference = model.length - newDays;
                            if (model.length > newDays) {
                                model.splice(model.length - 1, difference);
                            } else {
                                var lastDay = model[model.length - 1];
                                for (i = lastDay; i < lastDay + difference; ++i) {
                                    model.push(i + 1);
                                }
                            }
                        }

                        tumbler.setCurrentIndexAt(0, Math.min(newDays - 1, previousIndex));
                    }
                }
                TumblerColumn {
                    id: monthColumn
                    width: characterMetrics.width * 3 + tumbler.delegateTextMargins
                    model: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
                    onCurrentIndexChanged: tumblerDayColumn.updateModel()
                }
                TumblerColumn {
                    width: characterMetrics.width * 4 + tumbler.delegateTextMargins
                    model: ListModel {
                        Component.onCompleted: {
                            for (var i = 2000; i < 2100; ++i) {
                                append({value: i.toString()});
                            }
                        }
                    }
                }
            }
        }

        FontLoader {
            id: openSans
            source: "qrc:/fonts/OpenSans-Regular.ttf"
         }

        property var componentMap: {
            "CircularGauge": circularGauge,
            "DelayButton": delayButton,
            "Dial": dial,
            "Gauge": gauge,
            "PieMenu": pieMenu,
            "StatusIndicator": statusIndicator,
            "ToggleButton": toggleButton,
            "Tumbler": tumbler
        }

        StackView {
            id: stackView
            anchors.fill: parent

            initialItem: ListView {
                model: ListModel {
                    ListElement {
                        title: "CircularGauge"
                    }
                    ListElement {
                        title: "DelayButton"
                    }
                    ListElement {
                        title: "Dial"
                    }
                    ListElement {
                        title: "Gauge"
                    }
                    ListElement {
                        title: "PieMenu"
                    }
                    ListElement {
                        title: "StatusIndicator"
                    }
                    ListElement {
                        title: "ToggleButton"
                    }
                    ListElement {
                        title: "Tumbler"
                    }
                }

                delegate: Button {
                    width: stackView.width
                    height: root.height * 0.125
                    text: title

                    style: BlackButtonStyle {
                        fontColor: root.darkFontColor
                        rightAlignedIconSource: "qrc:/images/icon-go.png"
                    }

                    onClicked: {
                        if (stackView.depth == 1) {
                            // Only push the control view if we haven't already pushed it...
                            stackView.push({item: componentMap[title]});
                            stackView.currentItem.forceActiveFocus();
                        }
                    }
                }
            }
        }
    }