gallery.qml Example File

gallery/qml/gallery.qml
/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, 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 Layout.alignment: Qt.AlignCenter 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" Layout.alignment: Qt.AlignCenter } } ColumnLayout { id: trebleColumn width: parent.width height: (dialColumn.height - dialColumn.spacing) / 2 spacing: height * 0.025 Dial { id: dial2 Layout.alignment: Qt.AlignCenter Layout.fillWidth: true Layout.fillHeight: true stepSize: 1 maximumValue: 10 style: DialStyle { labelInset: outerRadius * 0 } } ControlLabel { id: trebleText text: "Treble" Layout.alignment: Qt.AlignCenter } } } 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(); } } } } } }