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 prevTemp: GlobalState.selectedRoom.temperature property alias thermoOn: powerBtn.checked property int maxTemp: Units.fahrenheitToTemperatureUnit(90) property int minTemp: Units.fahrenheitToTemperatureUnit(50) property int smallestAngle : 25; function setTemperature(t : real) { _setTemperatureImpl(t, false) } function setTemperatureWithoutAnimation(t : real) { _setTemperatureImpl(t, true) } 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 } Item { width: wheelImg.width height: width anchors.horizontalCenter: parent.horizontalCenter y: Theme.thermoY Image { id: wheelImg source: root.thermoOn ? "jog.png" : "jog-off.png" } Row { clip: true id: thermoText anchors.centerIn: parent width: Theme.roomViewTempWidth height: Theme.roomViewTempHeight AnimatedDigit { id: tens visible: root.thermoOn; stopAnimation: true value: GlobalState.selectedRoom.temperature / 10 } AnimatedDigit { id: ones visible: root.thermoOn; stopAnimation: true value: GlobalState.selectedRoom.temperature % 10 } } Image { id: digitMaskTop anchors.top: thermoText.top anchors.horizontalCenter: parent.horizontalCenter source: "digitMaskTop.png" } Image { id: digitMaskBottom anchors.bottom: thermoText.bottom anchors.horizontalCenter: parent.horizontalCenter source: "digitMaskBottom.png" } Text { visible: root.thermoOn color: "#3d464d" anchors.top: thermoText.top anchors.left: thermoText.right anchors.topMargin: Theme.isBig ? 13 : 11 text: Units.temperatureSymbol font.pixelSize: Theme.wheelTempUnitSize } MouseArea { visible: root.thermoOn width: parent.width height: parent.height / 2 Image { source: parent.pressed ? "pressed-bg-up.png" : "" anchors.centerIn: parent } ColorizedImage { source: "temp-up-pressed.png" anchors.centerIn: parent anchors.verticalCenterOffset: Theme.tempControlOffset color: parent.pressed ? ColorStyle.blue : ColorStyle.greyMedium3 } onClicked: { root.setTemperature(GlobalState.selectedRoom.temperature+1); } } MouseArea { visible: root.thermoOn width: parent.width height: parent.height / 2 anchors.bottom: parent.bottom Image { source: parent.pressed ? "pressed-bg-down.png" : "" anchors.centerIn: parent } ColorizedImage { source: "temp-down-pressed.png" anchors.centerIn: parent anchors.verticalCenterOffset: -Theme.tempControlOffset color: parent.pressed ? ColorStyle.blue : ColorStyle.greyMedium3 } onClicked: { root.setTemperature(GlobalState.selectedRoom.temperature-1); } } Image { id: thermoHandle visible: root.thermoOn z: 10 source: "images/inner-circle.png" property real angle: (90 + root.smallestAngle + (GlobalState.selectedRoom.temperature - root.minTemp)/(root.maxTemp-root.minTemp) * (360-2*root.smallestAngle) ) * 2 * Math.PI / 360 x : parent.width/2 - width/2 + Theme.wheelSize * Math.cos(angle) y : parent.height/2 - height/2 + Theme.wheelSize * Math.sin(angle) MouseArea { anchors.centerIn: parent width: Theme.thermoHandleSize height: Theme.thermoHandleSize property real pressedX: 0 property real pressedY: 0 onPressed: { pressedX = mouse.x pressedY = mouse.y } 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); } Image { source: "thermo-handle.png" visible: parent.pressed anchors.centerIn: parent; } } } } Text { visible: root.thermoOn || Theme.isBig text: { switch (GlobalState.selectedRoom.status) { case Room.Heating: return qsTr("Heating") case Room.Cooling: return qsTr("Cooling") default: return qsTr("OFF") } } color: GlobalState.selectedRoom.status == Room.Off ? ColorStyle.greyDark1 : ColorStyle.greyDark4 font.pixelSize: Theme.wheelStatusTextSize anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.bottomMargin: Theme.isBig ? 36 : 12 } ColorizedImage { visible: root.thermoOn source: "status-small.png" anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.bottomMargin: Theme.isBig ? 15 : 0 color: GlobalState.selectedRoom.status == Room.Heating ? ColorStyle.pinkyRed : ColorStyle.blue } Column { anchors.leftMargin: Theme.roomButtonMargin anchors.left: parent.left y: Theme.roomButtonsY spacing: Theme.roomButtonSpacing RoomControlButton { id: autoBtn icon.source: "auto-on.png" enabled: root.thermoOn checked: GlobalState.selectedRoom.auto_ onCheckedChanged: { if (checked) { dryerBtn.checked = fanBtn.checked = ecoBtn.checked = streamerBtn.checked = false; } GlobalState.selectedRoom.auto_ = checked } } RoomControlButton { id: dryerBtn icon.source: "dryer-on.png" enabled: root.thermoOn checked: GlobalState.selectedRoom.dryer onCheckedChanged: { if (checked) { autoBtn.checked = false } GlobalState.selectedRoom.dryer = checked } } FanControlButton { id: fanBtn enabled: root.thermoOn currentRoom: GlobalState.selectedRoom } } Column { anchors.rightMargin: Theme.roomButtonMargin anchors.right: parent.right y: Theme.roomButtonsY spacing: Theme.roomButtonSpacing RoomControlButton { id: powerBtn icon.source: "power-on.png" checked: GlobalState.selectedRoom.power pulsing: !checked onCheckedChanged: { GlobalState.selectedRoom.power = checked } } RoomControlButton { id: ecoBtn icon.source: "eco-on.png" enabled: root.thermoOn checked: GlobalState.selectedRoom.eco onCheckedChanged: { if (checked) { autoBtn.checked = false } GlobalState.selectedRoom.eco = checked } } RoomControlButton { id: streamerBtn icon.source: "streamer-on.png" enabled: root.thermoOn checked: GlobalState.selectedRoom.streamer onCheckedChanged: { if (checked) { autoBtn.checked = false } GlobalState.selectedRoom.streamer = checked } } } }