C
Qt Quick Ultralite Thermostat Demo
/****************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** 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 http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/import QtQuick 2.15 import QtQuickUltralite.Extras 2.0 import Thermo 1.0 ThermoView { id: root property int maxTemp: Units.fahrenheitToTemperatureUnit(90) property int minTemp: Units.fahrenheitToTemperatureUnit(50) property int prevTemp: GlobalState.selectedRoom.temperature property int smallestAngle: 25 property alias thermoOn: powerBtn.checked function _setTemperatureImpl(t: real, stopAnimation: bool) { GlobalState.selectedRoom.temperature = Math.min(Math.max(Math.round(t), minTemp), maxTemp); tens.stopAnimation = stopAnimation; ones.stopAnimation = stopAnimation; tens.reversed = GlobalState.selectedRoom.temperature < prevTemp; ones.reversed = GlobalState.selectedRoom.temperature < prevTemp; prevTemp = GlobalState.selectedRoom.temperature; } function setTemperature(t: real) { _setTemperatureImpl(t, false); } function setTemperatureWithoutAnimation(t: real) { _setTemperatureImpl(t, true); } Item { anchors.horizontalCenter: parent.horizontalCenter height: width width: wheelImg.width y: Theme.thermoY Image { id: wheelImg source: root.thermoOn ? "jog.png" : "jog-off.png" } Row { id: thermoText anchors.centerIn: parent clip: true height: Theme.roomViewTempHeight width: Theme.roomViewTempWidth AnimatedDigit { id: tens stopAnimation: true value: GlobalState.selectedRoom.temperature / 10 visible: root.thermoOn } AnimatedDigit { id: ones stopAnimation: true value: GlobalState.selectedRoom.temperature % 10 visible: root.thermoOn } } Image { id: digitMaskTop anchors.horizontalCenter: parent.horizontalCenter anchors.top: thermoText.top source: "digitMaskTop.png" } Image { id: digitMaskBottom anchors.bottom: thermoText.bottom anchors.horizontalCenter: parent.horizontalCenter source: "digitMaskBottom.png" } Text { anchors.left: thermoText.right anchors.top: thermoText.top anchors.topMargin: Theme.isBig ? 13 : 11 color: "#3d464d" font.pixelSize: Theme.wheelTempUnitSize text: Units.temperatureSymbol visible: root.thermoOn } MouseArea { height: parent.height / 2 visible: root.thermoOn width: parent.width onClicked: { root.setTemperature(GlobalState.selectedRoom.temperature + 1); } Image { anchors.centerIn: parent source: parent.pressed ? "pressed-bg-up.png" : "" } ColorizedImage { anchors.centerIn: parent anchors.verticalCenterOffset: Theme.tempControlOffset color: parent.pressed ? ColorStyle.blue : ColorStyle.greyMedium3 source: "temp-up-pressed.png" } } MouseArea { anchors.bottom: parent.bottom height: parent.height / 2 visible: root.thermoOn width: parent.width onClicked: { root.setTemperature(GlobalState.selectedRoom.temperature - 1); } Image { anchors.centerIn: parent source: parent.pressed ? "pressed-bg-down.png" : "" } ColorizedImage { anchors.centerIn: parent anchors.verticalCenterOffset: -Theme.tempControlOffset color: parent.pressed ? ColorStyle.blue : ColorStyle.greyMedium3 source: "temp-down-pressed.png" } } Image { id: thermoHandle property real angle: (90 + root.smallestAngle + (GlobalState.selectedRoom.temperature - root.minTemp) / (root.maxTemp - root.minTemp) * (360 - 2 * root.smallestAngle)) * 2 * Math.PI / 360 source: "images/inner-circle.png" visible: root.thermoOn x: parent.width / 2 - width / 2 + Theme.wheelSize * Math.cos(angle) y: parent.height / 2 - height / 2 + Theme.wheelSize * Math.sin(angle) z: 10 MouseArea { property real pressedX: 0 property real pressedY: 0 anchors.centerIn: parent height: Theme.thermoHandleSize width: Theme.thermoHandleSize onPositionChanged: { var px = mouse.x - pressedX + x + width / 2 + parent.x - parent.parent.width / 2; var py = mouse.y - pressedY + y + height / 2 + parent.y - parent.parent.height / 2; var d = Math.sqrt(px * px + py * py); if (d < Theme.wheelSize * 0.6) return; // too far from the position var angle = Math.atan2(px / d, py / d) * 360 / (Math.PI * 2); angle = (360 - angle); while (angle > 360) angle -= 360; var temperature = root.minTemp + (angle - root.smallestAngle) * (root.maxTemp - root.minTemp) / (360 - 2 * root.smallestAngle); root.setTemperatureWithoutAnimation(temperature); } onPressed: { pressedX = mouse.x; pressedY = mouse.y; } Image { anchors.centerIn: parent source: "thermo-handle.png" visible: parent.pressed } } } } Text { anchors.bottom: parent.bottom anchors.bottomMargin: Theme.isBig ? 36 : 12 anchors.horizontalCenter: parent.horizontalCenter color: GlobalState.selectedRoom.status == Room.Off ? ColorStyle.greyDark1 : ColorStyle.greyDark4 font.pixelSize: Theme.wheelStatusTextSize text: { switch (GlobalState.selectedRoom.status) { //% "Heating" case Room.Heating: return qsTrId("id-heating"); //% "Cooling" case Room.Cooling: return qsTrId("id-cooling"); //% "Off" default: return qsTrId("id-off"); } } visible: root.thermoOn || Theme.isBig } ColorizedImage { anchors.bottom: parent.bottom anchors.bottomMargin: Theme.isBig ? 15 : 0 anchors.horizontalCenter: parent.horizontalCenter color: GlobalState.selectedRoom.status == Room.Heating ? ColorStyle.pinkyRed : ColorStyle.blue source: "status-small.png" visible: root.thermoOn } Column { anchors.left: parent.left anchors.leftMargin: Theme.roomButtonMargin spacing: Theme.roomButtonSpacing y: Theme.roomButtonsY RoomControlButton { id: autoBtn checked: GlobalState.selectedRoom.auto_ enabled: root.thermoOn icon.source: "auto-on.png" onCheckedChanged: { if (checked) { dryerBtn.checked = fanBtn.checked = ecoBtn.checked = streamerBtn.checked = false; } GlobalState.selectedRoom.auto_ = checked; } } RoomControlButton { id: dryerBtn checked: GlobalState.selectedRoom.dryer enabled: root.thermoOn icon.source: "dryer-on.png" onCheckedChanged: { if (checked) { autoBtn.checked = false; } GlobalState.selectedRoom.dryer = checked; } } FanControlButton { id: fanBtn currentRoom: GlobalState.selectedRoom enabled: root.thermoOn } } Column { anchors.right: parent.right anchors.rightMargin: Theme.roomButtonMargin spacing: Theme.roomButtonSpacing y: Theme.roomButtonsY RoomControlButton { id: powerBtn checked: GlobalState.selectedRoom.power icon.source: "power-on.png" pulsing: !checked onCheckedChanged: { GlobalState.selectedRoom.power = checked; } } RoomControlButton { id: ecoBtn checked: GlobalState.selectedRoom.eco enabled: root.thermoOn icon.source: "eco-on.png" onCheckedChanged: { if (checked) { autoBtn.checked = false; } GlobalState.selectedRoom.eco = checked; } } RoomControlButton { id: streamerBtn checked: GlobalState.selectedRoom.streamer enabled: root.thermoOn icon.source: "streamer-on.png" onCheckedChanged: { if (checked) { autoBtn.checked = false; } GlobalState.selectedRoom.streamer = checked; } } } }