| /**************************************************************************** |
| ** |
| ** 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(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |