From: Suchinton Chakravarty Date: Thu, 10 Oct 2024 12:46:07 +0000 (+0530) Subject: Add Tire Pressure, Keypad elements and misc. UI Changes X-Git-Tag: 19.90.0~3 X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F01%2F30401%2F8;p=src%2Fagl-demo-control-panel.git Add Tire Pressure, Keypad elements and misc. UI Changes - Increased slider grab handle size - Add floating menu for Tire Pressure UI - Show errow in Playback toggle when CAN interface is not available - Update Half gauges to show Unit and logo correctly - Update App resources - Add new tumbler input for HVAC temp - Add new get function to KuksaClient to get Tire Pressure unit and Current value to increment Fixes: - Check for vcar dbc file at '/etc/kuksa-dbc-feeder/' - Increase font size in Settings page - Allow for tumbler/ spin wheel values to wrap around Bug-AGL: SPEC-5161 Change-Id: I2386bf7dc762b09b83cef1be104a35d6afc0a704 Signed-off-by: Suchinton Chakravarty --- diff --git a/.gitignore b/.gitignore index 4249446..865ea5a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ map.html test/ control-panel/ res_rc.py -Scripts/can_messages.txt Scripts/agl-vcar.dbc +assets/can_messages.txt \ No newline at end of file diff --git a/QMLWidgets/Full_Gauge/SpeedGauge.qml b/QMLWidgets/Full_Gauge/SpeedGauge.qml index 263e7f1..02531b7 100644 --- a/QMLWidgets/Full_Gauge/SpeedGauge.qml +++ b/QMLWidgets/Full_Gauge/SpeedGauge.qml @@ -94,9 +94,26 @@ Item { function drawProgress(ctx, center, progress) { ctx.lineWidth = 20; + + // Create a linear gradient + var gradient = ctx.createLinearGradient( + center.x + gaugeRadius * Math.cos(startAngle), + center.y + gaugeRadius * Math.sin(startAngle), + center.x + gaugeRadius * Math.cos(startAngle + fullAngle), + center.y + gaugeRadius * Math.sin(startAngle + fullAngle) + ); + + // Set gradient stops + gradient.addColorStop(0.3, "#00FF00"); // Green color + gradient.addColorStop(0.3, primaryColor); // Primary color + gradient.addColorStop(0.3, "#FFD700"); // Yellow color + gradient.addColorStop(1, "#FF0000"); // Red color + ctx.beginPath(); ctx.arc(center.x, center.y, gaugeRadius, startAngle, startAngle + (progress / 270) * fullAngle); - ctx.strokeStyle = primaryColor; + + // Apply the gradient to the stroke style + ctx.strokeStyle = gradient; ctx.stroke(); } @@ -118,17 +135,17 @@ Item { } function drawProgressTick(ctx, center, progress) { - + ctx.lineWidth = tickLength * 3 ctx.strokeStyle = '#FFFFFF' ctx.beginPath() - + const progressAngle = startAngle + (progress / 270) * fullAngle const x1 = center.x + gaugeRadius * Math.cos(progressAngle) const y1 = center.y + gaugeRadius * Math.sin(progressAngle) const x2 = center.x + (gaugeRadius - tickLength * 1.5) * Math.cos(progressAngle) const y2 = center.y + (gaugeRadius - tickLength * 1.5) * Math.sin(progressAngle) - + ctx.moveTo(x1, y1) ctx.lineTo(x2, y2) ctx.stroke() diff --git a/QMLWidgets/Half_Gauge/CoolantGauge.qml b/QMLWidgets/Half_Gauge/CoolantGauge.qml index 6e1d583..634647d 100644 --- a/QMLWidgets/Half_Gauge/CoolantGauge.qml +++ b/QMLWidgets/Half_Gauge/CoolantGauge.qml @@ -5,10 +5,11 @@ Item { width: 200 height: 200 - property real value: 80 + property real value: 0 property real minValue: 0 property real maxValue: 120 property string unit: "°C" + property string iconSource: "qrc:/Carbon_Icons/carbon_icons/temperature--water.svg" property color primaryColor: "#16CCBA" property color secondaryColor: "#00000000" @@ -34,12 +35,12 @@ Item { var center = Qt.point(width / 2, height / 2) var side = Math.min(width, height) var radius = (side - side * 0.25) / 2 - var startAngle = Math.PI * 2 / 3 - var fullAngle = Math.PI * 2 / 3 + var startAngle = Math.PI * 5 / 4 + var fullAngle = Math.PI * 1 / 2 var progressAngle = startAngle + (degree / 270) * fullAngle ctx.reset() - ctx.lineCap = 'square' + ctx.lineCap = 'round' // background arc ctx.lineWidth = 25 @@ -86,21 +87,20 @@ Item { id: gaugePercentage anchors.verticalCenter: gaugeText.verticalCenter anchors.left: gaugeText.right - text: "%" + text: unit font.pixelSize: 0.15 * Math.min(root.width, root.height) font.bold: true color: "#FFFFFF" } - Text { - id: gaugeUnit + Image { + source: iconSource anchors.top: gaugeText.bottom anchors.horizontalCenter: gaugeText.horizontalCenter - - text: unit - font.pixelSize: 18 - font.bold: true - color: "#FFFFFF" + width: 0.15 * Math.min(root.width, root.height) + fillMode: Image.PreserveAspectFit + // antialiasing: true + antialiasing: true } Behavior on value { diff --git a/QMLWidgets/Half_Gauge/FuelGauge.qml b/QMLWidgets/Half_Gauge/FuelGauge.qml index 21ac4cd..f0ea7d0 100644 --- a/QMLWidgets/Half_Gauge/FuelGauge.qml +++ b/QMLWidgets/Half_Gauge/FuelGauge.qml @@ -5,10 +5,11 @@ Item { width: 200 height: 200 - property real value: 80 + property real value: 0 property real minValue: 0 property real maxValue: 100 - property string unit: "NA" + property string unit: "%" + property string iconSource: "qrc:/Images/Images/fuel-icon.png" property color primaryColor: "#16CCBA" property color secondaryColor: "#00000000" @@ -36,12 +37,12 @@ Item { var center = Qt.point(width / 2, height / 2) var side = Math.min(width, height) var radius = (side - side * 0.25) / 2 - var startAngle = Math.PI * 2 / 3 - var fullAngle = Math.PI * 2 / 3 + var startAngle = Math.PI * 5 / 4 + var fullAngle = Math.PI * 1 / 2 var progressAngle = startAngle + (degree / 270) * fullAngle ctx.reset() - ctx.lineCap = 'square' + ctx.lineCap = 'round' // background arc ctx.lineWidth = 25 @@ -90,21 +91,20 @@ Item { anchors.verticalCenter: gaugeText.verticalCenter anchors.left: gaugeText.right - text: "%" + text: unit font.pixelSize: 0.15 * Math.min(root.width, root.height) font.bold: true color: "#FFFFFF" } - Text { - id: gaugeUnit + Image { + source: iconSource anchors.top: gaugeText.bottom anchors.horizontalCenter: gaugeText.horizontalCenter - - text: unit - font.pixelSize: 18 - font.bold: true - color: "#FFFFFF" + width: 0.15 * Math.min(root.width, root.height) + fillMode: Image.PreserveAspectFit + // antialiasing: true + antialiasing: true } Behavior on value { diff --git a/QMLWidgets/Temp_Tumbler/TempTumbler.qml b/QMLWidgets/Temp_Tumbler/TempTumbler.qml new file mode 100644 index 0000000..612d9a3 --- /dev/null +++ b/QMLWidgets/Temp_Tumbler/TempTumbler.qml @@ -0,0 +1,159 @@ +import QtQuick 2.9 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.2 + +Rectangle { + width: frame.implicitWidth + height: frame.implicitHeight + + // save colors in variables + property color backgroundColor: "#131313" + property color background_alt: "#2A2827" + property color buttonColor: "#6C6C85" + property color highlight: "#4BD7D6" + + // store icons from qrc in variables + property string iconUp: "qrc:/Carbon_Icons/carbon_icons/temperature--frigid.svg" + property string iconDown: "qrc:/Carbon_Icons/carbon_icons/temperature--hot.svg" + + color: backgroundColor + + signal valueChanged(int newValue) + + FontMetrics { + id: fontMetrics + } + + Component { + id: delegateComponent + + Label { + text: model.number + opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pixelSize: fontMetrics.font.pixelSize * parent.width / fontMetrics.font.pixelSize / 3 + color: highlight + font.bold: true + } + } + + Frame { + id: frame + padding: 0 + anchors.centerIn: parent + anchors.fill: parent + + Rectangle { + anchors.fill: parent + color: backgroundColor + radius: 10 + } + + Column { + spacing: 10 + anchors.fill: parent + + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 10 + + Button { + width: parent.width + height: parent.height / 6 + + Rectangle { + width: parent.width + height: parent.height + color: buttonColor + radius: 10 + + Image { + source: iconUp + anchors.centerIn: parent + sourceSize.width: parent.width / 2 + sourceSize.height: parent.height / 2 + fillMode: Image.PreserveAspectFit + smooth: true + } + } + onClicked: { + // if we are at the top of the list, set the index to the last element + if (valueTumbler.currentIndex == 0) { + valueTumbler.currentIndex = valueTumbler.model.count - 1; + } + else { + valueTumbler.currentIndex -= 1; + } + } + } + + Tumbler { + id: valueTumbler + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + height: parent.height / 2 + model: ListModel { + ListElement { number: 16 } + ListElement { number: 17 } + ListElement { number: 18 } + ListElement { number: 19 } + ListElement { number: 20 } + ListElement { number: 21 } + ListElement { number: 22 } + ListElement { number: 23 } + ListElement { number: 24 } + ListElement { number: 25 } + ListElement { number: 26 } + ListElement { number: 27 } + ListElement { number: 28 } + ListElement { number: 29 } + ListElement { number: 30 } + ListElement { number: 31 } + ListElement { number: 32 } + } + + onCurrentIndexChanged: { + valueChanged(model.get(currentIndex).number); + } + + delegate: delegateComponent + + Rectangle { + width: parent.width + height: parent.height + color: background_alt + radius: 10 + } + } + + Button { + width: parent.width + height: parent.height / 6 + + Rectangle { + width: parent.width + height: parent.height + color: buttonColor + radius: 10 + + Image { + source: iconDown + anchors.centerIn: parent + sourceSize.width: parent.width / 2 + sourceSize.height: parent.height / 2 + fillMode: Image.PreserveAspectFit + smooth: true + } + } + onClicked: { + if (valueTumbler.currentIndex == 16) { + valueTumbler.currentIndex = 0; + } + else { + valueTumbler.currentIndex += 1; + } + } + } + } + } +} \ No newline at end of file diff --git a/QMLWidgets/Tire_Pressure/TirePressure.qml b/QMLWidgets/Tire_Pressure/TirePressure.qml new file mode 100644 index 0000000..0102fba --- /dev/null +++ b/QMLWidgets/Tire_Pressure/TirePressure.qml @@ -0,0 +1,247 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +Item { + id: root + width: 400 + height: 400 + + property string carImage: "./assets/car-top.png" + property string defaultTire: "./assets/DefaultTire.svg" + property string selectedTire: "./assets/SelectedTire.svg" + + property color highlight: "#4BD7D6" + property color defaultColor: "#6C6C85" + property color darkbg: "#131313" + + property int selectedTireIndex: -1 + + // Move these functions here so they're accessible to all buttons + function resetAllButtons() { + selectedTireIndex = -1; + button0.background.color = defaultColor; + button1.background.color = defaultColor; + button2.background.color = defaultColor; + button3.background.color = defaultColor; + + tireImage0.source = defaultTire; + tireImage1.source = defaultTire; + tireImage2.source = defaultTire; + tireImage3.source = defaultTire; + } + + function selectButton(index) { + selectedTireIndex = index; + + switch(index) { + case 0: + button0.background.color = highlight; + tireImage0.source = selectedTire; + break; + case 1: + button1.background.color = highlight; + tireImage1.source = selectedTire; + break; + case 2: + button2.background.color = highlight; + tireImage2.source = selectedTire; + break; + case 3: + button3.background.color = highlight; + tireImage3.source = selectedTire; + break; + } + + // Reset other buttons + for (var i = 0; i < 4; i++) { + if (i !== index) { + var button = eval("button" + i); + button.background.color = defaultColor; + eval("tireImage" + i).source = defaultTire; + } + } + } + + Rectangle { + anchors.fill: parent + color: darkbg + z: 0 + + Image { + id: car + source: carImage + fillMode: Image.PreserveAspectFit + anchors.fill: parent + anchors.centerIn: parent + z: 1 + } + + GridLayout { + id: buttonGrid + anchors.centerIn: parent + columns: 2 + rows: 2 + + Button { + id: button0 + Layout.preferredWidth: car.width / 2 + Layout.preferredHeight: car.height / 2 + + background: Rectangle { + color: defaultColor + opacity: 0.5 + radius: 15 + z: 1 + } + + Rectangle { + width: parent.width / 2 + height: parent.height / 2 + color: "transparent" + anchors.fill: parent + z: 2 + + Image { + id: tireImage0 + source: defaultTire + sourceSize.height: parent.height / 2 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: parent.height * 0.32 + } + } + + onClicked: handleButtonClick(0) + + function handleButtonClick(index) { + if (selectedTireIndex === index) { + resetAllButtons(); + } else { + selectButton(index); + } + } + } + + Button { + id: button1 + Layout.preferredWidth: car.width / 2 + Layout.preferredHeight: car.height / 2 + + background: Rectangle { + color: defaultColor + opacity: 0.5 + radius: 15 + z: 1 + } + + Rectangle { + width: parent.width / 2 + height: parent.height / 2 + color: "transparent" + anchors.fill: parent + z: 2 + + Image { + id: tireImage1 + source: defaultTire + sourceSize.height: parent.height / 2 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: parent.height * 0.28 + } + } + + onClicked: handleButtonClick(1) + + function handleButtonClick(index) { + if (selectedTireIndex === index) { + resetAllButtons(); + } else { + selectButton(index); + } + } + } + + Button { + id: button2 + Layout.preferredWidth: car.width / 2 + Layout.preferredHeight: car.height / 2 + + background: Rectangle { + color: defaultColor + opacity: 0.5 + radius: 15 + z: 1 + } + + Rectangle { + width: parent.width / 2 + height: parent.height / 2 + color: "transparent" + anchors.fill: parent + z: 2 + + Image { + id: tireImage2 + source: defaultTire + sourceSize.height: parent.height / 2 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: parent.height * 0.32 + } + } + + onClicked: handleButtonClick(2) + + function handleButtonClick(index) { + if (selectedTireIndex === index) { + resetAllButtons(); + } else { + selectButton(index); + } + } + } + + Button { + id: button3 + Layout.preferredWidth: car.width / 2 + Layout.preferredHeight: car.height / 2 + + background: Rectangle { + color: defaultColor + opacity: 0.5 + radius: 15 + z: 1 + } + + Rectangle { + width: parent.width / 2 + height: parent.height / 2 + color: "transparent" + anchors.fill: parent + z: 2 + + Image { + id: tireImage3 + source: defaultTire + sourceSize.height: parent.height / 2 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: parent.height * 0.28 + } + } + + onClicked: handleButtonClick(3) + + function handleButtonClick(index) { + if (selectedTireIndex === index) { + resetAllButtons(); + } else { + selectButton(index); + } + } + } + } + } +} diff --git a/QMLWidgets/Tire_Pressure/assets/DefaultTire.svg b/QMLWidgets/Tire_Pressure/assets/DefaultTire.svg new file mode 100644 index 0000000..89ac4b6 --- /dev/null +++ b/QMLWidgets/Tire_Pressure/assets/DefaultTire.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/QMLWidgets/Tire_Pressure/assets/SelectedTire.svg b/QMLWidgets/Tire_Pressure/assets/SelectedTire.svg new file mode 100644 index 0000000..0a653e2 --- /dev/null +++ b/QMLWidgets/Tire_Pressure/assets/SelectedTire.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QMLWidgets/Tire_Pressure/assets/car-top.png b/QMLWidgets/Tire_Pressure/assets/car-top.png new file mode 100644 index 0000000..9283e0b Binary files /dev/null and b/QMLWidgets/Tire_Pressure/assets/car-top.png differ diff --git a/Widgets/HVACPage.py b/Widgets/HVACPage.py index d101e15..8371dfe 100644 --- a/Widgets/HVACPage.py +++ b/Widgets/HVACPage.py @@ -6,7 +6,11 @@ import os import sys from PyQt6 import uic -from PyQt6.QtWidgets import QApplication, QListWidget, QSlider, QPushButton +from PyQt6.QtWidgets import QApplication, QFrame, QSlider, QPushButton, QWidget +from PyQt6 import QtWidgets +from PyQt6.QtQuickWidgets import QQuickWidget +from PyQt6.QtQuick import QQuickItem +from PyQt6.QtCore import QUrl current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -14,7 +18,6 @@ current_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.dirname(current_dir)) - Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/HVAC.ui")) # ======================================== @@ -29,14 +32,22 @@ class HVAC_Paths(): self.rightTemp = "Vehicle.Cabin.HVAC.Station.Row1.Passenger.Temperature" self.rightFanSpeed = "Vehicle.Cabin.HVAC.Station.Row1.Passenger.FanSpeed" - # temperatureList contains values from 32 to 16 - self.temperatureList = [str(i) + "°C" for i in range(32, 15, -1)] +def TumblerWidget(): + """QWidget for controlling HVAC Temperature.""" + + TumblerQML = os.path.join(current_dir, "../QMLWidgets/Temp_Tumbler/TempTumbler.qml") + + TumblerWidget = QQuickWidget() + TumblerWidget.setSource(QUrl.fromLocalFile(TumblerQML)) + TumblerWidget.setResizeMode(QQuickWidget.ResizeMode.SizeRootObjectToView) + TumblerWidget.setSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) + return TumblerWidget class HVACWidget(Base, Form): """ A widget for controlling HVAC settings. - + Inherits from Base and Form. """ @@ -52,40 +63,29 @@ class HVACWidget(Base, Form): self.setupUi(self) self.HVAC = HVAC_Paths() - self.kuksa_client = KuksaClient() - self.leftTempList = self.findChild(QListWidget, "leftTempList") - self.leftTempList.addItems(self.HVAC.temperatureList) - self.leftTempList.setCurrentRow(0) - self.leftTempList.itemClicked.connect(self.leftTempListClicked) - self.leftTempList.itemSelectionChanged.connect( - self.leftTempListClicked) - self.leftTempList.wheelEvent = lambda event: None - - self.rightTempList = self.findChild(QListWidget, "rightTempList") - self.rightTempList.addItems(self.HVAC.temperatureList) - self.rightTempList.setCurrentRow(0) - self.rightTempList.itemClicked.connect(self.rightTempListClicked) - self.rightTempList.itemSelectionChanged.connect( - self.rightTempListClicked) - self.rightTempList.wheelEvent = lambda event: None - - self.leftTempUp = self.findChild(QPushButton, "leftTempUp") - self.leftTempUp.clicked.connect( - lambda: self.leftTempList.setCurrentRow(self.leftTempList.currentRow() - 1)) - - self.leftTempDown = self.findChild(QPushButton, "leftTempDown") - self.leftTempDown.clicked.connect( - lambda: self.leftTempList.setCurrentRow(self.leftTempList.currentRow() + 1)) - - self.rightTempUp = self.findChild(QPushButton, "rightTempUp") - self.rightTempUp.clicked.connect( - lambda: self.rightTempList.setCurrentRow(self.rightTempList.currentRow() - 1)) - - self.rightTempDown = self.findChild(QPushButton, "rightTempDown") - self.rightTempDown.clicked.connect( - lambda: self.rightTempList.setCurrentRow(self.rightTempList.currentRow() + 1)) + leftFrame = self.findChild(QFrame, "leftFrame") + + # Create left temperature tumbler + self.LeftTempTumbler = TumblerWidget() + + # Connect the left tumbler signal to the handler + self.LeftTempTumbler.rootObject().valueChanged.connect(self.onLeftTempChanged) + + # Replace placeholder LeftTemp_Placeholder with the LeftTempTumbler widget + leftFrame.layout().replaceWidget(self.findChild(QWidget, "LeftTemp_Placeholder"), self.LeftTempTumbler) + + rightFrame = self.findChild(QFrame, "rightFrame") + + # Create right temperature tumbler + self.RightTempTumbler = TumblerWidget() + + # Connect the right tumbler signal to the handler + self.RightTempTumbler.rootObject().valueChanged.connect(self.onRightTempChanged) + + # Replace placeholder RightTemp_Placeholder with the RightTempTumbler widget + rightFrame.layout().replaceWidget(self.findChild(QWidget, "RightTemp_Placeholder"), self.RightTempTumbler) self.leftFanSpeed_slider = self.findChild( QSlider, "leftFanSpeed_slider") @@ -97,28 +97,27 @@ class HVACWidget(Base, Form): self.rightFanSpeed_slider.valueChanged.connect( self.rightFanSpeed_sliderChanged) - def leftTempListClicked(self): - """ - Handles the event when an item in the left temperature list is clicked. - Sets the corresponding VSS signal to the selected temperature value. - """ - - self.setTemperature(self.leftTempList, self.HVAC.leftTemp) + def changeTemperature(self, tumbler_widget, change): + """Change tumbler value by incrementing or decrementing.""" + + # use the inc_Value method from the QML object if change is 1 then increment, else decrement + # Access the root object of the QML component + self.LeftTempTumbler.rootObject().property("inc_Value", change) - def rightTempListClicked(self): - """ - Handles the event when an item in the right temperature list is clicked. - Sets the corresponding VSS signal to the selected temperature value. - """ + def onLeftTempChanged(self, newValue): + """Slot to handle changes in left temperature tumbler.""" + + print(f"Left Temperature Tumbler stopped at value: {newValue}°C") + self.setTemperature(newValue, self.HVAC.leftTemp) - self.setTemperature(self.rightTempList, self.HVAC.rightTemp) + def onRightTempChanged(self, newValue): + """Slot to handle changes in right temperature tumbler.""" + + print(f"Right Temperature Tumbler stopped at value: {newValue}°C") + self.setTemperature(newValue, self.HVAC.rightTemp) - def setTemperature(self, list_widget, path): - item = list_widget.currentItem() - if item is not None: - list_widget.scrollToItem(item) - self.kuksa_client.set(path, item.text()[:-2], "targetValue") - print(item.text()) + def setTemperature(self, temp, path): + self.kuksa_client.set(path, str(temp), "targetValue") def leftFanSpeed_sliderChanged(self): """ @@ -140,10 +139,8 @@ class HVACWidget(Base, Form): self.kuksa_client.set(self.HVAC.rightFanSpeed, str(value), "targetValue") print(value) - if __name__ == '__main__': - import sys app = QApplication(sys.argv) w = HVACWidget() w.show() - sys.exit(app.exec()) + sys.exit(app.exec()) \ No newline at end of file diff --git a/Widgets/ICPage.py b/Widgets/ICPage.py index b40177c..0f44703 100644 --- a/Widgets/ICPage.py +++ b/Widgets/ICPage.py @@ -10,7 +10,7 @@ from PyQt6 import uic, QtCore, QtWidgets from PyQt6.QtWidgets import QApplication from PyQt6.QtGui import QIcon, QPixmap, QPainter from PyQt6.QtCore import QObject, pyqtSignal, QThread -from PyQt6.QtWidgets import QWidget, QFrame +from PyQt6.QtWidgets import QWidget, QFrame, QDockWidget from PyQt6.QtQuickWidgets import QQuickWidget import threading @@ -40,10 +40,14 @@ def Gauge(gaugeType): - A QQuickWidget object representing the gauge widget. """ - RPM_GaugeQML = os.path.join(current_dir, "../QMLWidgets/Full_Gauge/RPMGauge.qml") - Speed_GaugeQML = os.path.join(current_dir, "../QMLWidgets/Full_Gauge/SpeedGauge.qml") - Fuel_GaugeQML = os.path.join(current_dir, "../QMLWidgets/Half_Gauge/FuelGauge.qml") - Coolant_GaugeQML = os.path.join(current_dir, "../QMLWidgets/Half_Gauge/CoolantGauge.qml") + RPM_GaugeQML = os.path.join( + current_dir, "../QMLWidgets/Full_Gauge/RPMGauge.qml") + Speed_GaugeQML = os.path.join( + current_dir, "../QMLWidgets/Full_Gauge/SpeedGauge.qml") + Fuel_GaugeQML = os.path.join( + current_dir, "../QMLWidgets/Half_Gauge/FuelGauge.qml") + Coolant_GaugeQML = os.path.join( + current_dir, "../QMLWidgets/Half_Gauge/CoolantGauge.qml") gauge = QQuickWidget() if gaugeType == "RPM": @@ -57,11 +61,14 @@ def Gauge(gaugeType): elif gaugeType == "Coolant": gauge.setSource(QtCore.QUrl(Coolant_GaugeQML)) - + gauge.setResizeMode(QQuickWidget.ResizeMode.SizeRootObjectToView) - + gauge.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding) + return gauge + class IC_Paths(): def __init__(self): self.speed = "Vehicle.Speed" @@ -73,6 +80,7 @@ class IC_Paths(): self.coolantTemp = "Vehicle.Powertrain.CombustionEngine.ECT" self.selectedGear = "Vehicle.Powertrain.Transmission.SelectedGear" + class ICWidget(Base, Form): """ This class represents the ICWidget which is a widget for the AGL Demo Control Panel. @@ -100,7 +108,8 @@ class ICWidget(Base, Form): self.Frame_1 = self.findChild(QWidget, "frame_1") self.Fuel_Gauge_Frame = self.findChild(QFrame, "fuel_gauge_frame") - self.Coolant_Gauge_Frame = self.findChild(QFrame, "coolant_gauge_frame") + self.Coolant_Gauge_Frame = self.findChild( + QFrame, "coolant_gauge_frame") self.Script_toggle = AnimatedToggle() @@ -125,7 +134,8 @@ class ICWidget(Base, Form): self.driveGroupBtns.buttonClicked.connect(self.driveBtnClicked) - Speed_Gauge_Placeholder = self.findChild(QWidget, "Speed_Gauge_Placeholder") + Speed_Gauge_Placeholder = self.findChild( + QWidget, "Speed_Gauge_Placeholder") self.Speed_Gauge = Gauge("Speed") self.Frame_1.layout().replaceWidget(Speed_Gauge_Placeholder, self.Speed_Gauge) @@ -133,7 +143,8 @@ class ICWidget(Base, Form): self.Speed_slider.setMinimum(0) self.Speed_slider.setMaximum(240) - RPM_Gauge_Placeholder = self.findChild(QWidget, "RPM_Gauge_Placeholder") + RPM_Gauge_Placeholder = self.findChild( + QWidget, "RPM_Gauge_Placeholder") self.RPM_Gauge = Gauge("RPM") self.Frame_1.layout().replaceWidget(RPM_Gauge_Placeholder, self.RPM_Gauge) @@ -141,26 +152,23 @@ class ICWidget(Base, Form): self.RPM_slider.setMinimum(0) self.RPM_slider.setMaximum(8000) - fuel_Gauge_Placeholder = self.findChild(QWidget, "fuel_Gauge_Placeholder") + fuel_Gauge_Placeholder = self.findChild( + QWidget, "fuel_Gauge_Placeholder") self.Fuel_Gauge = Gauge("Fuel") - self.Fuel_Gauge_Frame.layout().replaceWidget(fuel_Gauge_Placeholder, self.Fuel_Gauge) + self.Fuel_Gauge_Frame.layout().replaceWidget( + fuel_Gauge_Placeholder, self.Fuel_Gauge) - coolant_Gauge_Placeholder = self.findChild(QWidget, "coolant_Gauge_Placeholder") + coolant_Gauge_Placeholder = self.findChild( + QWidget, "coolant_Gauge_Placeholder") self.Coolant_Gauge = Gauge("Coolant") - self.Coolant_Gauge_Frame.layout().replaceWidget(coolant_Gauge_Placeholder, self.Coolant_Gauge) - - self.mousePressEvent = lambda event: print("Mouse Pressed") - self.mouseReleaseEvent = lambda event: print("Mouse Released") - - self.Coolant_Gauge.mousePressEvent = self.mousePressEvent - self.Coolant_Gauge.mouseReleaseEvent = self.mouseReleaseEvent + self.Coolant_Gauge_Frame.layout().replaceWidget( + coolant_Gauge_Placeholder, self.Coolant_Gauge) self.coolantTemp_slider.valueChanged.connect( self.update_coolantTemp_monitor) self.fuelLevel_slider.valueChanged.connect( self.update_fuelLevel_monitor) - self.Script_toggle.clicked.connect(self.handle_Script_toggle) self.leftIndicatorBtn.setCheckable(True) self.rightIndicatorBtn.setCheckable(True) self.hazardBtn.setCheckable(True) @@ -169,14 +177,36 @@ class ICWidget(Base, Form): self.rightIndicatorBtn.toggled.connect(self.rightIndicatorBtnClicked) self.hazardBtn.toggled.connect(self.hazardBtnClicked) - self.Playback = CAN_playback() - self.Playback_connections() + self.Script_toggle.clicked.connect(self.handle_Script_toggle) + + try: + self.Playback = CAN_playback() + self.Playback_connections() + except Exception as e: + logging.error(f"Error creating playback object {e}") + + self.TirePressureDock = self.findChild(QDockWidget, "TirePressureDock") + self.TirePressureBtn = self.findChild( + QtWidgets.QPushButton, "TirePressureBtn") + self.TirePressureBtn.clicked.connect(self.toggle_TirePressureDock) + + def toggle_TirePressureDock(self): + if self.TirePressureBtn.isChecked(): + self.Hide_TirePressure(True) + else: + self.Hide_TirePressure(False) + + def Hide_TirePressure(self, bool_arg): + widthExtended = 0 if bool_arg else 400 + self.TirePressureDock.setFixedWidth(widthExtended) + def Playback_connections(self): self.Playback.speedUpdate.connect(self.set_Vehicle_Speed) self.Playback.gearUpdate.connect(self.playback_set_Vehicle_Gear) self.Playback.engineSpeedUpdate.connect(self.set_Vehicle_RPM) - self.Playback.indicatorUpdate.connect(self.playback_set_Vehicle_Indicators) + self.Playback.indicatorUpdate.connect( + self.playback_set_Vehicle_Indicators) def playback_set_Vehicle_Gear(self, gear): if gear == "P": @@ -239,7 +269,8 @@ class ICWidget(Base, Form): Updates the coolant temperature monitor with the current coolant temperature value. """ coolantTemp = int(self.coolantTemp_slider.value()) - self.Coolant_Gauge.rootObject().setProperty('value', coolantTemp/100) + gaugeValue = coolantTemp / 100 + self.Coolant_Gauge.rootObject().setProperty('value', gaugeValue) try: self.kuksa_client.set( self.IC.coolantTemp, str(coolantTemp), 'value') @@ -265,7 +296,8 @@ class ICWidget(Base, Form): """ hazardIcon = QPixmap(":/Images/Images/hazard.png") painter = QPainter(hazardIcon) - painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) + painter.setCompositionMode( + QPainter.CompositionMode.CompositionMode_SourceIn) if self.hazardBtn.isChecked(): color = QtCore.Qt.GlobalColor.yellow @@ -294,7 +326,8 @@ class ICWidget(Base, Form): """ leftIndicatorIcon = QPixmap(":/Images/Images/left.png") painter = QPainter(leftIndicatorIcon) - painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) + painter.setCompositionMode( + QPainter.CompositionMode.CompositionMode_SourceIn) if self.leftIndicatorBtn.isChecked(): color = QtCore.Qt.GlobalColor.green @@ -318,7 +351,8 @@ class ICWidget(Base, Form): """ rightIndicatorIcon = QPixmap(":/Images/Images/right.png") painter = QPainter(rightIndicatorIcon) - painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) + painter.setCompositionMode( + QPainter.CompositionMode.CompositionMode_SourceIn) if self.rightIndicatorBtn.isChecked(): color = QtCore.Qt.GlobalColor.green @@ -356,15 +390,28 @@ class ICWidget(Base, Form): def handle_Script_toggle(self): if config.file_playback_enabled(): + if not config.can_interface_enabled(): + self.Script_toggle.showError() + self.Script_toggle.setChecked(False) + return + try: + self.Playback = CAN_playback() + self.Playback_connections() + except Exception as e: + self.Script_toggle.showError() + logging.error(f"Error creating playback object {e}") + return + if self.Script_toggle.isChecked(): # start the playback thread self.thread = QThread() self.Playback.moveToThread(self.thread) self.thread.started.connect(self.Playback.playback_messages) self.thread.start() - # hide sliders + # hide sliders from the layout, their space will be taken by the playback widgets self.Speed_slider.hide() self.RPM_slider.hide() + # set default values for coolent and fuel self.coolantTemp_slider.setValue(90) self.fuelLevel_slider.setValue(50) @@ -448,6 +495,7 @@ class ICWidget(Base, Form): else: print("Unknown button checked!") + class AccelerationFns(): def calculate_speed(time, acceleration) -> int: # acceleration = 60 / 5 # acceleration from 0 to 60 in 5 seconds diff --git a/Widgets/Keypad.py b/Widgets/Keypad.py index ad0c17e..264bb5d 100644 --- a/Widgets/Keypad.py +++ b/Widgets/Keypad.py @@ -1,7 +1,8 @@ import os import sys from PyQt6 import uic -from PyQt6.QtWidgets import QApplication, QWidget, QPushButton +from PyQt6.QtWidgets import QPushButton +from PyQt6.QtWidgets import QApplication, QWidget import requests from urllib.parse import urljoin diff --git a/Widgets/TirePressure.py b/Widgets/TirePressure.py new file mode 100644 index 0000000..0f3efce --- /dev/null +++ b/Widgets/TirePressure.py @@ -0,0 +1,129 @@ +# Copyright (C) 2024 Suchinton Chakravarty +# Copyright (C) 2024 Konsulko Group +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +from PyQt6 import uic +from PyQt6.QtWidgets import QApplication, QPushButton, QWidget, QLabel +from PyQt6.QtQuickWidgets import QQuickWidget +from PyQt6.QtWidgets import QSizePolicy +from PyQt6.QtCore import QUrl +import logging + +current_dir = os.path.dirname(os.path.abspath(__file__)) + +# ======================================== + +sys.path.append(os.path.dirname(current_dir)) + + +Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/TirePressure.ui")) + +# ======================================== + +from extras.KuksaClient import KuksaClient +import res_rc + +class TirePressure_Paths(): + def __init__(self): + self.Tires = { + 0 : "Vehicle.Chassis.Axle.Row1.Wheel.Left.Tire.Pressure", + 1 : "Vehicle.Chassis.Axle.Row1.Wheel.Right.Tire.Pressure", + 2 : "Vehicle.Chassis.Axle.Row2.Wheel.Left.Tire.Pressure", + 3 : "Vehicle.Chassis.Axle.Row2.Wheel.Right.Tire.Pressure" + } + +def TireSelectionWidget(): + """ + A widget for selecting the tire to control. + + Returns: + - A QListWidget. + """ + + QMLPath = os.path.join(current_dir, "../QMLWidgets/Tire_Pressure/TirePressure.qml") + widget = QQuickWidget() + widget.setSource(QUrl.fromLocalFile(QMLPath)) + widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + widget.setResizeMode(QQuickWidget.ResizeMode.SizeRootObjectToView) + return widget + +class TirePressure(Base, Form): + """ + A widget for controlling TirePressure settings. + + Inherits from Base and Form. + """ + + def __init__(self, parent=None): + """ + Initializes the TirePressureWidget. + + Args: + - parent: The parent widget. Defaults to None. + """ + + super(self.__class__, self).__init__(parent) + self.setupUi(self) + + self.TirePressurePath = TirePressure_Paths() + self.kuksa_client = KuksaClient() + self.TireSelector = TireSelectionWidget() + + placeholder = self.findChild(QWidget, "TS_Placeholher") + frame = self.findChild(QWidget, "frame") + frame.layout().replaceWidget(placeholder, self.TireSelector) + self.TPIncreaseBtn = self.findChild(QPushButton, "TPIncreaseBtn") + self.TPDecreaseBtn = self.findChild(QPushButton, "TPDecreaseBtn") + self.TPUnit = self.findChild(QLabel, "TPUnit") + + self.TPIncreaseBtn.clicked.connect(self.increase_pressure) + self.TPDecreaseBtn.clicked.connect(self.decrease_pressure) + + def get_Current(self, tire): + """ + Initializes the TirePressure widget. + """ + + try: + self.TPUnit = self.kuksa_client.get("Vehicle.Cabin.Infotainment.HMI.TirePressureUnit") + return self.kuksa_client.get(self.TirePressurePath.Tires[tire]) + except Exception as e: + logging.error(f"Error getting tire pressure values: {e}") + + + def increase_pressure(self): + """ + Increases the pressure of the selected tire. + """ + + selected_tire = self.TireSelector.rootObject().property("selectedTireIndex") + + current_pressure = self.get_Current(selected_tire) + if current_pressure is None: + return + else: + self.kuksa_client.setValues({self.TirePressurePath.Tires[selected_tire]: current_pressure + 1}) + + + def decrease_pressure(self): + """ + Decreases the pressure of the selected tire. + """ + + selected_tire = self.TireSelector.rootObject().property("selectedTireIndex") + + current_pressure = self.get_Current(selected_tire) + if current_pressure is None: + return + else: + self.kuksa_client.setValues({self.TirePressurePath.Tires[selected_tire]: current_pressure - 1}) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + w = TirePressure() + w.show() + sys.exit(app.exec()) diff --git a/assets/Images/tire-pressure.svg b/assets/Images/tire-pressure.svg new file mode 100644 index 0000000..0a4e236 --- /dev/null +++ b/assets/Images/tire-pressure.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/res.qrc b/assets/res.qrc index 58ac6ec..d3f0c91 100644 --- a/assets/res.qrc +++ b/assets/res.qrc @@ -40,6 +40,7 @@ carbon_icons/windy--strong-disabled.svg + Images/tire-pressure.svg Images/HMI_HVAC_Fan_Icon.svg Images/AGL_Icons_LaneDeparture_white.svg Images/AGL_Icons_CruiseControl_white.svg diff --git a/extras/KuksaClient.py b/extras/KuksaClient.py index 772fd50..dbffd93 100644 --- a/extras/KuksaClient.py +++ b/extras/KuksaClient.py @@ -119,7 +119,7 @@ class KuksaClient(QThread): """ if self.client is None: - #logging.error("Kuksa client is None, try reconnecting") + logging.error("Kuksa client is None, try reconnecting") return if not self.client.checkConnection(): @@ -133,3 +133,34 @@ class KuksaClient(QThread): except Exception as e: logging.error(f"Error sending values to kuksa {e}") threading.Thread(target=self.set_instance).start() + + def get(self, path=None): + """ + Gets VSS value. + + Parameters: + ----------- + path : str + The VSS signal path. + + Returns: + -------- + Any + The value of the VSS signal. + """ + + if self.client is None: + logging.error("Kuksa client is None, try reconnecting") + return + + if not self.client.checkConnection(): + logging.error("Client is not connected, try reconnecting") + threading.Thread(target=self.set_instance).start() + return + + try: + return self.client.getValue(path) + except Exception as e: + logging.error(f"Error getting value from kuksa {e}") + threading.Thread(target=self.set_instance).start() + return None diff --git a/extras/config.ini b/extras/config.ini index 9d443da..409de83 100644 --- a/extras/config.ini +++ b/extras/config.ini @@ -1,10 +1,11 @@ [default] -fullscreen-mode = false +fullscreen-mode = true hvac-enabled = true steering-wheel-enabled = true file-playback-enabled = true -file-playback-path = -can-interface = +file-playback-path = +dbc-file-path = +can-interface = [vss-server] ip = localhost diff --git a/extras/config.py b/extras/config.py index 7540e61..8df3497 100644 --- a/extras/config.py +++ b/extras/config.py @@ -67,6 +67,12 @@ PLAYBACK_FILE_PATHS = check_paths( os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/can_messages.txt")) ) +DBC_FILE_PATHS = check_paths( + config.get('default', 'dbc-file-path', fallback=None), + "/etc/kuksa-dbc-feeder/agl-vcar.dbc", + os.path.abspath(os.path.join(os.path.dirname(__file__), "../Scripts/agl-vcar.dbc")) +) + CA_PATH = next((path for path, exists in CA_PATHS.items() if exists), None) WS_TOKEN = next((path for path, exists in WS_TOKEN_PATHS.items() if exists), None) GRPC_TOKEN = next((path for path, exists in GRPC_TOKEN_PATHS.items() if exists), None) @@ -177,7 +183,14 @@ def get_playback_file(): config.write(configfile) return os.path.join(os.path.dirname(__file__), "can_messages.txt") - + +# Function to get the dbc file path from config.ini +def get_dbc_file(): + if DBC_FILE_PATHS: + return DBC_FILE_PATHS + else: + raise ValueError("DBC file path not found") + # Function to get the can interface name from config.ini def get_can_interface(): print(config.get('default', 'can-interface', fallback=None)) diff --git a/ui/HVAC.ui b/ui/HVAC.ui index eff65e0..906b122 100644 --- a/ui/HVAC.ui +++ b/ui/HVAC.ui @@ -6,8 +6,8 @@ 0 0 - 815 - 575 + 950 + 587 @@ -63,39 +63,37 @@ border-radius: 8px; } -QSlider::sub-page:vertical { - background-color: #131313 ; /* black */ - height: 20px; - width: 28px; - margin: 2px; - border: 1px solid #6C6C85 ; /* pastel purple */ - border-radius: 8px; -} - QSlider::groove:vertical { - border-radius: 8px; - width: 28px; - margin: 2px; + background-color: #4BD7D6 ; /* light blue */ border: 1px solid #6C6C85 ; /* pastel purple */ - background-color: #4BD7D6 ; /* light blue */ + width: 40px; + border-radius: 20px; } -QSlider::groove:vertical:hover { - background-color: rgb(55, 62, 76); + +QSlider::sub-page:vertical { + border: 1px solid #6C6C85; /* pastel purple */ + background-color: #131313; /* black */ + width: 36px; + margin-top: 0px; /* Adjusted for better alignment */ + margin-bottom: -20px; /* Space below the sub-page */ + border-radius: 18px; } + QSlider::handle:vertical { - background-color: #d5d5d5; - height: 15px; - width: 20px; - border-radius: 5px; -} -QSlider::handle:vertical:hover { - background-color: #6C6C85 ; /* pastel purple */ -} -QSlider::handle:vertical:pressed { - background-color: #4BD7D6 ; /* light blue */ + height: 28px; + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #eee, stop:1 #ccc); + border: 1px solid #777; + width: 28px; + margin-top: 5px; + margin-bottom: 5px; + margin-left: 5px; + margin-right: 5px; + border-radius: 15px; } + QScrollBar:horizontal { min-width: 240px; height: 13px; @@ -205,23 +203,7 @@ QListWidget::item:hover { QFrame::Raised - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - + @@ -260,23 +242,7 @@ QListWidget::item:hover { - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - + @@ -291,11 +257,11 @@ QListWidget::item:hover { QFrame::Raised - + - 16 + 18 75 true true @@ -306,7 +272,7 @@ QListWidget::item:hover { - + Qt::Vertical @@ -322,53 +288,46 @@ QListWidget::item:hover { - - + + Qt::Vertical - QSizePolicy::Fixed + QSizePolicy::Preferred 20 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 + 40 - - + + - Qt::Horizontal + Qt::Vertical QSizePolicy::Fixed - 40 + 20 20 - - + + + + + 0 + 0 + + QFrame::StyledPanel @@ -376,175 +335,20 @@ QListWidget::item:hover { QFrame::Raised - - - - - - - - :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg - - - - 40 - 40 - - - - - - + + - + 0 0 - - - 0 - 152 - - - - - 60 - 152 - - - - - 14 - 75 - true - true - - - - Qt::StrongFocus - - - Qt::LeftToRight - - - false - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed - - - false - - - QAbstractItemView::DragOnly - - - QAbstractItemView::SingleSelection - - - Qt::ElideMiddle - - - QAbstractItemView::ScrollPerPixel - - - QListView::Snap - - - false - - - QListView::Adjust - - - QListView::SinglePass - - - 1 - - - QListView::ListMode - - - true - - - true - - - Qt::AlignCenter - - - - - - - - - - - :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg - - - - 40 - 40 - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - + QFrame::StyledPanel @@ -578,7 +382,7 @@ QListWidget::item:hover { - 40 + 60 0 @@ -621,23 +425,7 @@ QListWidget::item:hover { - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - + @@ -652,7 +440,7 @@ QListWidget::item:hover { QFrame::Raised - + Qt::Vertical @@ -668,23 +456,7 @@ QListWidget::item:hover { - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - + QFrame::StyledPanel @@ -712,7 +484,7 @@ QListWidget::item:hover { - 40 + 60 0 @@ -734,39 +506,22 @@ QListWidget::item:hover { - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed + + + + + 18 + 75 + true + true + - - - 40 - 20 - + + Right Controls - + - + Qt::Vertical @@ -782,22 +537,7 @@ QListWidget::item:hover { - - - - - 16 - 75 - true - true - - - - Right Controls - - - - + Qt::Vertical @@ -813,8 +553,14 @@ QListWidget::item:hover { - - + + + + + 0 + 0 + + QFrame::StyledPanel @@ -822,132 +568,8 @@ QListWidget::item:hover { QFrame::Raised - - - - - - - - :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg - - - - 40 - 40 - - - - - - - - - 0 - 0 - - - - - 0 - 152 - - - - - 60 - 152 - - - - - 14 - 75 - true - true - - - - Qt::StrongFocus - - - Qt::LeftToRight - - - false - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed - - - false - - - QAbstractItemView::DragOnly - - - QAbstractItemView::ContiguousSelection - - - Qt::ElideMiddle - - - QAbstractItemView::ScrollPerPixel - - - QListView::Snap - - - QListView::Adjust - - - QListView::SinglePass - - - 1 - - - QListView::ListMode - - - true - - - Qt::AlignCenter - - - - - - - - - - - :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg - - - - 40 - 40 - - - + + diff --git a/ui/IC.ui b/ui/IC.ui index 256eb81..961fc04 100644 --- a/ui/IC.ui +++ b/ui/IC.ui @@ -13,6 +13,9 @@ Form + + false + *{ border: none; @@ -44,59 +47,59 @@ QPushButton:pressed { QSlider::groove:horizontal { background-color: #131313 ; /* black */ border: 1px solid #6C6C85 ; /* pastel purple */ - height: 28px; - border-radius: 8px; + height: 40px; + border-radius: 20px; } QSlider::sub-page:horizontal { background-color: #4BD7D6 ; /* light blue */ - height: 28px; - border-radius: 5px; + border: 1px solid #6C6C85 ; /* pastel purple */ + height: 36px; + margin-right: -20px; + border-radius: 18px; } QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc); border: 1px solid #777; - width: 20px; - margin-top: -2px; - margin-bottom: -2px; - border-radius: 8px; -} - -QSlider::sub-page:vertical { - background-color: #131313 ; /* black */ - height: 20px; width: 28px; - margin: 4px; - border: 1px solid #6C6C85 ; /* pastel purple */ - border-radius: 8px; + margin-top: 5px; + margin-bottom: 5px; + margin-left: 5px; + margin-right: 5px; + border-radius: 15px; } QSlider::groove:vertical { - border-radius: 8px; - width: 28px; - margin: 4px; + background-color: #4BD7D6 ; /* light blue */ border: 1px solid #6C6C85 ; /* pastel purple */ - background-color: #4BD7D6 ; /* light blue */ + width: 40px; + border-radius: 20px; } -QSlider::groove:vertical:hover { - background-color: rgb(55, 62, 76); + +QSlider::sub-page:vertical { + border: 1px solid #6C6C85; /* pastel purple */ + background-color: #131313; /* black */ + width: 36px; + margin-top: 0px; /* Adjusted for better alignment */ + margin-bottom: -20px; /* Space below the sub-page */ + border-radius: 18px; } + QSlider::handle:vertical { - background-color: #d5d5d5; - height: 15px; - width: 20px; - border-radius: 5px; -} -QSlider::handle:vertical:hover { - background-color: #6C6C85 ; /* pastel purple */ -} -QSlider::handle:vertical:pressed { - background-color: #4BD7D6 ; /* light blue */ + height: 28px; + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #eee, stop:1 #ccc); + border: 1px solid #777; + width: 28px; + margin-top: 5px; + margin-bottom: 5px; + margin-left: 5px; + margin-right: 5px; + border-radius: 15px; } - QScrollBar:horizontal { min-width: 240px; height: 13px; @@ -165,7 +168,27 @@ QLCDNumber { QFrame::Raised - + + + + false + + + QDockWidget::NoDockWidgetFeatures + + + + false + + + + + + + + + + @@ -183,10 +206,10 @@ QLCDNumber { QFrame::StyledPanel - QFrame::Raised + QFrame::Sunken - + @@ -247,27 +270,6 @@ QLCDNumber { - - - - - 0 - 0 - - - - - Open Sans - 75 - true - true - - - - Speed (Kmph) - - - @@ -281,27 +283,6 @@ QLCDNumber { - - - - - 0 - 0 - - - - - Open Sans - 75 - true - true - - - - Engine RPM - - - @@ -374,7 +355,7 @@ QLCDNumber { QFrame::Raised - + @@ -391,39 +372,24 @@ QLCDNumber { - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Horizontal + + + + - - QSizePolicy::Fixed + + + :/Images/Images/hazard.png:/Images/Images/hazard.png - + - 20 - 20 + 60 + 60 - + - + false @@ -452,27 +418,36 @@ QLCDNumber { - - - - + + + + Qt::Horizontal - - - :/Images/Images/hazard.png:/Images/Images/hazard.png + + + 40 + 20 + - + + + + + + Qt::Horizontal + + - 60 - 60 + 40 + 20 - + - + @@ -499,7 +474,7 @@ QLCDNumber { 4 - + @@ -513,24 +488,23 @@ QLCDNumber { 0 + + Qt::LeftToRight + Qt::Vertical - - - - - - - 0 - 0 - + + false - - + + false + + + QSlider::NoTicks - - :/Carbon_Icons/carbon_icons/temperature--water.svg + + 0 @@ -553,7 +527,7 @@ QLCDNumber { - + @@ -571,7 +545,7 @@ QLCDNumber { 4 - + @@ -590,6 +564,9 @@ QLCDNumber { true + + false + 0 @@ -607,33 +584,6 @@ QLCDNumber { - - - - - 0 - 0 - - - - - 12 - - - - QFrame::NoFrame - - - - - - :/Carbon_Icons/carbon_icons/rain-drop.svg - - - false - - - @@ -656,72 +606,7 @@ QLCDNumber { - - - - - 0 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 18 - 75 - true - true - - - - Demo Mode - - - - - - - - - - - - - - + @@ -741,6 +626,9 @@ QLCDNumber { Qt::Horizontal + + QSizePolicy::Expanding + 167 @@ -911,6 +799,9 @@ QLCDNumber { Qt::Horizontal + + QSizePolicy::Expanding + 168 @@ -922,6 +813,115 @@ QLCDNumber { + + + + + 0 + 50 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + 50 + 50 + + + + + Open Sans + 20 + 75 + false + true + + + + + + + + :/Images/Images/tire-pressure.svg:/Images/Images/tire-pressure.svg + + + + 50 + 50 + + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 18 + 75 + true + true + + + + Demo Mode + + + + + + + + + + + + + @@ -930,6 +930,14 @@ QLCDNumber { + + + TirePressure + QWidget +
Widgets/TirePressure
+ 1 +
+
diff --git a/ui/Settings_Window.ui b/ui/Settings_Window.ui index d59cae6..0043bb1 100644 --- a/ui/Settings_Window.ui +++ b/ui/Settings_Window.ui @@ -175,7 +175,7 @@ QCheckBox:indicator:disabled { - 14 + 18 75 true true @@ -190,7 +190,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -205,7 +205,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -217,7 +217,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -245,7 +245,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -254,7 +254,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -263,7 +263,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -275,7 +275,7 @@ QCheckBox:indicator:disabled { - 14 + 18 75 true true @@ -290,7 +290,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -302,7 +302,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -334,7 +334,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -343,7 +343,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -355,7 +355,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -364,7 +364,7 @@ QCheckBox:indicator:disabled { - 14 + 18 @@ -426,7 +426,7 @@ QCheckBox:indicator:disabled { - 16 + 18 75 true true @@ -451,7 +451,7 @@ QCheckBox:indicator:disabled { - 16 + 18 75 true true @@ -506,7 +506,7 @@ QCheckBox:indicator:disabled { - 14 + 18 75 true @@ -558,7 +558,7 @@ QCheckBox:indicator:disabled { - 16 + 18 75 true true diff --git a/ui/TirePressure.ui b/ui/TirePressure.ui new file mode 100644 index 0000000..7387ff3 --- /dev/null +++ b/ui/TirePressure.ui @@ -0,0 +1,330 @@ + + + HVAC + + + + 0 + 0 + 407 + 590 + + + + + 0 + 0 + + + + Form + + + *{ + border: none; + background-color: transparent; + background: none; + padding: 0; + margin: 0; + color: #fff; +} + +#scrollAreaWidgetContents{ + background-color: #131313 ; /* black */ +} + +#centralwidget{ + background-color: #131313 ; /* black */ +} + +#centralwidget QPushButton{ + background-color: #6C6C85 ; /* pastel purple */ + padding: 5px 10px; + border-radius: 10px; +} + +#centralwidget QPushButton:pressed { + background-color: #4BD7D6 ; /* light blue */ +} + +#centralwidget QSlider::groove:horizontal { + border: 1px solid #6C6C85 ; /* pastel purple */ + height: 15px; + border-radius: 8px; +} + +#centralwidget QSlider::sub-page:horizontal { + background-color: #4BD7D6 ; /* light blue */ + height: 15px; + border-radius: 5px; +} + +#centralwidget QSlider::handle:horizontal { + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, + stop:0 #eee, stop:1 #ccc); + border: 1px solid #777; + width: 20px; + margin-top: -2px; + margin-bottom: -2px; + border-radius: 8px; +} + +QSlider::sub-page:vertical { + background-color: #131313 ; /* black */ + height: 20px; + width: 28px; + margin: 2px; + border: 1px solid #6C6C85 ; /* pastel purple */ + border-radius: 8px; +} + +QSlider::groove:vertical { + border-radius: 8px; + width: 28px; + margin: 2px; + border: 1px solid #6C6C85 ; /* pastel purple */ + background-color: #4BD7D6 ; /* light blue */ +} +QSlider::groove:vertical:hover { + background-color: rgb(55, 62, 76); +} +QSlider::handle:vertical { + background-color: #d5d5d5; + height: 15px; + width: 20px; + border-radius: 5px; +} +QSlider::handle:vertical:hover { + background-color: #6C6C85 ; /* pastel purple */ +} +QSlider::handle:vertical:pressed { + background-color: #4BD7D6 ; /* light blue */ +} + + +QScrollBar:horizontal { + min-width: 240px; + height: 13px; + } + + QScrollBar:vertical { + min-height: 240px; + width: 13px; + } + + QScrollBar::groove { + background: 2A2827; /* dark grey */ + border-radius: 5px; + } + + QScrollBar::handle { + background: #4BD7D6 ; /* light blue */ + border-radius: 5px; + } + + QScrollBar::handle:horizontal { + width: 25px; + } + + QScrollBar::handle:vertical { + height: 25px; scrollAreaWidgetContents + } + +#leftControls{ + background: #041F2B ; /* dark blue */ + border-radius: 10px; +} + +#rightControls{ + background: #041F2B ; /* dark blue */ + border-radius: 10px; +} + + +/*============================================*/ + +QListWidget { + min-height: 150px; + max-height: 150px; + background-color: #131313 ; /* black */ + border: 1px solid #6C6C85 ; /* pastel purple */ + border-radius: 8px; +} + +QListWidget::item { + height: 50px; + width: 50px; + border-radius: 8px; + text-align: center; +} + +QListWidget::item:selected { + background-color: #4BD7D6 ; /* light blue */ + border-radius: 8px; +} + +QListWidget::item:selected:!active { + border-width: 0px; +} + +QListWidget::item:selected:active { + background-color: #4BD7D6 ; /* light blue */ +} + +QListWidget::item:selected:!focus { + color: black; + border-width: 0px; +} + +QListWidget::item:focus { + background-color: #6C6C85 ; /* pastel purple */ +} + +QListWidget::item:hover { + background-color: #6C6C85 ; /* pastel purple */ +} + + + + + + + + QFrame::NoFrame + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + :/Carbon_Icons/carbon_icons/subtract--alt.svg:/Carbon_Icons/carbon_icons/subtract--alt.svg + + + + 50 + 50 + + + + + + + + false + + + 1 + + + false + + + 2 + + + QLCDNumber::Flat + + + + + + + <html><head/><body><p><span style=" font-size:18pt;">lbp</span></p></body></html> + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + :/Carbon_Icons/carbon_icons/add--alt.svg:/Carbon_Icons/carbon_icons/add--alt.svg + + + + 50 + 50 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + <html><head/><body><p><span style=" font-size:18pt; font-weight:600; font-style:italic;">Tire Pressure</span></p></body></html> + + + true + + + + + + + + + + + + + + + +