/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the E-Bike demo project. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** 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. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import DataStore 1.0 import "./BikeStyle" Item { property string selectedComponent: "battery" property string bikeImageSource: "images/bike-battery.png" property string componentName: "Battery" property string componentStatusImageSource: "images/ok.png" property color statusLineColor: selectedComponent === "rearwheel" ? Colors.bikeInfoLineWarning : Colors.bikeInfoLineOk property int statusLineLength: 280 property string primaryDetails: "Health" property string primaryDetailsValue: "85%" property bool primaryDetailsOk: true property var activeComponent: batteryCircle function updateComponent() { if (selectedComponent === "") bikeImageSource = "images/bike.png"; else bikeImageSource = "images/bike-" + selectedComponent + ".png"; if (selectedComponent === "battery") { componentName = "Battery"; primaryDetails = "Health"; primaryDetailsValue = "85%"; primaryDetailsOk = true; statusLineLength = 280; } else if (selectedComponent === "brakes") { componentName = "Brakes"; primaryDetails = "Health"; primaryDetailsValue = "85%"; primaryDetailsOk = true; statusLineLength = 448; } else if (selectedComponent === "chain") { componentName = "Chain"; primaryDetails = "Health"; primaryDetailsValue = "85%"; primaryDetailsOk = true; statusLineLength = 0; } else if (selectedComponent === "gears") { componentName = "Gears"; primaryDetails = "Health"; primaryDetailsValue = "85%"; primaryDetailsOk = true; statusLineLength = 245; } else if (selectedComponent === "light") { componentName = "Light"; primaryDetails = "Health"; primaryDetailsValue = "85%"; primaryDetailsOk = true; statusLineLength = 300; } else if (selectedComponent === "frontwheel") { componentName = "Front wheel"; primaryDetails = "Tire pressure"; primaryDetailsValue = "6.8 bar / 100 psi"; primaryDetailsOk = true; statusLineLength = 340; } else if (selectedComponent === "rearwheel") { componentName = "Rear wheel"; primaryDetails = "Tire pressure"; primaryDetailsValue = "4.0 bar / 58 psi"; primaryDetailsOk = false; statusLineLength = 210; } } Text { id: bikeInfoText anchors { top: parent.top left: parent.left right: parent.right } height: UILayout.configurationItemHeight width: parent.width text: qsTr("BIKE INFO") font { family: "Montserrat, Medium" weight: Font.Medium pixelSize: UILayout.configurationTitleSize } color: Colors.tabTitleColor verticalAlignment: Text.AlignVCenter } ColumnSpacer { id: spacer anchors.top: bikeInfoText.bottom color: Colors.tabItemBorder } Image { id: bikeImage anchors { top: spacer.bottom right: parent.right rightMargin: -30 } source: bikeImageSource } Rectangle { id: brakesCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 43 horizontalCenter: bikeImage.left horizontalCenterOffset: 243 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "brakes" ? Colors.bikeInfoLineOk : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = brakesCircle; selectedComponent = "brakes" updateComponent() } } } Rectangle { id: lightCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 77 horizontalCenter: bikeImage.left horizontalCenterOffset: 252 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "light" ? Colors.bikeInfoLineOk : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = lightCircle; selectedComponent = "light" updateComponent() } } } Rectangle { id: batteryCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 106 horizontalCenter: bikeImage.left horizontalCenterOffset: 200 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "battery" ? Colors.bikeInfoLineOk : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = batteryCircle; selectedComponent = "battery" updateComponent() } } } Rectangle { id: gearsCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 143 horizontalCenter: bikeImage.left horizontalCenterOffset: 106 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "gears" ? Colors.bikeInfoLineOk : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = gearsCircle; selectedComponent = "gears" updateComponent() } } } Rectangle { id: rearWheelCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 144 horizontalCenter: bikeImage.left horizontalCenterOffset: 56 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "rearwheel" ? Colors.bikeInfoLineWarning : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = rearWheelCircle; selectedComponent = "rearwheel" updateComponent() } } Image { anchors.centerIn: parent source: "images/warning.png" } } Rectangle { id: frontWheelCircle width: 2 * UILayout.bikeInfoCircleRadius height: 2 * UILayout.bikeInfoCircleRadius radius: UILayout.bikeInfoCircleRadius anchors { verticalCenter: bikeImage.top verticalCenterOffset: 144 horizontalCenter: bikeImage.left horizontalCenterOffset: 322 } color: "transparent" border.width: UILayout.bikeInfoLineWidth border.color: selectedComponent === "frontwheel" ? Colors.bikeInfoLineOk : Colors.bikeInfoDeselected MouseArea { anchors.fill: parent onClicked: { activeComponent = frontWheelCircle; selectedComponent = "frontwheel" updateComponent() } } } Canvas { id: slantedLine anchors { left: statusLineHorizontal.right top: statusLineHorizontal.top right: activeComponent.horizontalCenter bottom: activeComponent.verticalCenter } onPaint: { var ctx = getContext("2d"); ctx.reset(); // Calculate line length and subtract circle radius var lineLength = Math.sqrt(slantedLine.width * slantedLine.width + slantedLine.height * slantedLine.height); lineLength -= UILayout.bikeInfoCircleRadius; // Calculate angle var angle = Math.atan2(slantedLine.height, slantedLine.width); // Calculate new endpoints var x = Math.cos(angle) * lineLength; var y = Math.sin(angle) * lineLength; ctx.lineCap = "round"; ctx.strokeStyle = statusLineColor; ctx.lineWidth = UILayout.bikeInfoLineWidth; ctx.beginPath(); ctx.moveTo(0, 1); ctx.lineTo(x, y); ctx.stroke(); } } Image { id: componentStatusImage anchors { verticalCenter: spacer.bottom verticalCenterOffset: (UILayout.bikeInfoComponentBaselineOffset + UILayout.bikeInfoComponentLineOffset) / 2 left: parent.left } source: componentStatusImageSource visible: selectedComponent != "" } Text { id: componentNameText anchors { baseline: spacer.bottom baselineOffset: UILayout.bikeInfoComponentBaselineOffset left: componentStatusImage.right leftMargin: 5 } font { family: "Montserrat, Medium" weight: Font.Medium pixelSize: UILayout.bikeInfoComponentHeaderTextSize } color: Colors.bikeInfoComponentHeader text: componentName visible: selectedComponent != "" } // The line goes here somehow Rectangle { id: statusLineHorizontal anchors { top: componentNameText.baseline topMargin: UILayout.bikeInfoComponentLineOffset left: parent.left } height: UILayout.bikeInfoLineWidth width: statusLineLength color: statusLineColor visible: selectedComponent != "" } Text { id: primaryDetailsText anchors { baseline: statusLineHorizontal.bottom baselineOffset: UILayout.bikeInfoLineDetailsMargin left: parent.left } font { family: "Montserrat, Light" weight: Font.Light pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: Colors.bikeInfoComponentText text: primaryDetails visible: selectedComponent != "" } Text { id: primaryDetailsValueText anchors { baseline: primaryDetailsText.baseline baselineOffset: UILayout.bikeInfoDetailsValueMargin left: parent.left } font { family: "Montserrat, Medium" weight: Font.Medium pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: primaryDetailsOk ? Colors.bikeInfoComponentOk : Colors.bikeInfoComponentWarning text: primaryDetailsValue visible: selectedComponent != "" } Text { id: lastMaintenanceText anchors { baseline: primaryDetailsValueText.baseline baselineOffset: UILayout.bikeInfoDetailsBaselineMargin left: parent.left } font { family: "Montserrat, Light" weight: Font.Light pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: Colors.bikeInfoComponentText text: qsTr("Last maintenance") visible: selectedComponent != "" } Text { id: lastMaintenanceValueText anchors { baseline: lastMaintenanceText.baseline baselineOffset: UILayout.bikeInfoDetailsValueMargin left: parent.left } font { family: "Montserrat, Medium" weight: Font.Medium pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: Colors.bikeInfoComponentOk text: "10/3/2017" visible: selectedComponent != "" } Text { id: nextMaintenanceText anchors { baseline: lastMaintenanceValueText.baseline baselineOffset: UILayout.bikeInfoDetailsBaselineMargin left: parent.left } font { family: "Montserrat, Light" weight: Font.Light pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: Colors.bikeInfoComponentText text: qsTr("Scheduled maintenance") visible: selectedComponent != "" } Text { id: nextMaintenanceValueText anchors { baseline: nextMaintenanceText.baseline baselineOffset: UILayout.bikeInfoDetailsValueMargin left: parent.left } font { family: "Montserrat, Medium" weight: Font.Medium pixelSize: UILayout.bikeInfoInfoHeaderTextSize } color: Colors.bikeInfoComponentOk text: "10/3/2018" visible: selectedComponent != "" } }