diff options
-rw-r--r-- | Main_Window.ui | 26 | ||||
-rw-r--r-- | QMLWidgets/Full_Gauge/RPMGauge.qml | 211 | ||||
-rw-r--r-- | QMLWidgets/Full_Gauge/SpeedGauge.qml | 175 | ||||
-rw-r--r-- | QMLWidgets/Half_Gauge/CoolantGauge.qml | 179 | ||||
-rw-r--r-- | QMLWidgets/Half_Gauge/FuelGauge.qml | 181 | ||||
-rw-r--r-- | QMLWidgets/Temp_Tumbler/TempTumbler.qml | 59 | ||||
-rw-r--r-- | Scripts/record_playback.py | 94 | ||||
-rw-r--r-- | Widgets/Dashboard.py | 11 | ||||
-rw-r--r-- | Widgets/HVACPage.py | 13 | ||||
-rw-r--r-- | Widgets/ICPage.py | 188 | ||||
-rw-r--r-- | Widgets/Keypad.py | 56 | ||||
-rw-r--r-- | assets/Images/Key_1.png | bin | 0 -> 10028 bytes | |||
-rw-r--r-- | assets/Images/Key_2.png | bin | 0 -> 13214 bytes | |||
-rw-r--r-- | assets/Images/Key_3.png | bin | 0 -> 13291 bytes | |||
-rw-r--r-- | assets/Images/Key_4.png | bin | 0 -> 12071 bytes | |||
-rw-r--r-- | assets/Images/flutter_demo.png | bin | 0 -> 2402 bytes | |||
-rw-r--r-- | assets/Images/grid.svg | 13 | ||||
-rw-r--r-- | assets/Images/qt_demo.png | bin | 0 -> 7410 bytes | |||
-rw-r--r-- | assets/res.qrc | 7 | ||||
-rw-r--r-- | extras/config.ini | 7 | ||||
-rw-r--r-- | extras/config.py | 19 | ||||
-rw-r--r-- | main.py | 24 | ||||
-rw-r--r-- | ui/Dashboard.ui | 90 | ||||
-rw-r--r-- | ui/IC.ui | 243 | ||||
-rw-r--r-- | ui/Keypad.ui | 274 |
25 files changed, 1182 insertions, 688 deletions
diff --git a/Main_Window.ui b/Main_Window.ui index 41500a8..8d57153 100644 --- a/Main_Window.ui +++ b/Main_Window.ui @@ -793,12 +793,13 @@ QStackedWidget{ </sizepolicy> </property> <property name="currentIndex"> - <number>3</number> + <number>4</number> </property> <widget class="Dashboard" name="Dashboard"/> <widget class="ICWidget" name="ICPage"/> <widget class="HVACWidget" name="HVACPage"/> <widget class="SteeringCtrlWidget" name="SteeringCtrlPage"/> + <widget class="KeypadWidget" name="KeypadPage"/> <widget class="settings" name="settingsPage"/> </widget> </item> @@ -1047,6 +1048,23 @@ QStackedWidget{ </property> </widget> </item> + <item> + <widget class="QPushButton" name="keypadButton"> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="assets/res.qrc"> + <normaloff>:/Images/Images/grid.svg</normaloff>:/Images/Images/grid.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>35</width> + <height>35</height> + </size> + </property> + </widget> + </item> </layout> </widget> </item> @@ -1149,6 +1167,12 @@ QStackedWidget{ <header>Widgets/Dashboard</header> <container>1</container> </customwidget> + <customwidget> + <class>KeypadWidget</class> + <extends>QWidget</extends> + <header>Widgets/Keypad</header> + <container>1</container> + </customwidget> </customwidgets> <resources> <include location="assets/res.qrc"/> diff --git a/QMLWidgets/Full_Gauge/RPMGauge.qml b/QMLWidgets/Full_Gauge/RPMGauge.qml index 382731d..e440a13 100644 --- a/QMLWidgets/Full_Gauge/RPMGauge.qml +++ b/QMLWidgets/Full_Gauge/RPMGauge.qml @@ -2,8 +2,8 @@ import QtQuick 2.9 Item {
id: root
- width: 400
- height: 400
+ width: 300
+ height: 300
property real value: 0
property real minValue: 0
@@ -13,7 +13,27 @@ Item { property color primaryColor: "#16CCBA"
property color secondaryColor: "#00000000"
property int animationDuration: 1000
- property real startAngle: 0
+ property real startAngle: Math.PI * 3 / 4
+ property real fullAngle: Math.PI * 3 / 2
+
+ property real gaugeRadius: 0
+ property real tickLength: 0
+
+ signal rpmValueChanged(int value)
+
+ Component.onCompleted: {
+ calculateGeometry();
+ updateGaugeValue(value); // Initialize the gauge display
+ }
+
+ onWidthChanged: calculateGeometry()
+ onHeightChanged: calculateGeometry()
+
+ function calculateGeometry() {
+ const side = Math.min(width, height);
+ gaugeRadius = (side - side * 0.20) / 2;
+ tickLength = gaugeRadius * 0.1;
+ }
Rectangle {
anchors.fill: parent
@@ -29,7 +49,6 @@ Item { sourceSize.height: width
fillMode: Image.PreserveAspectFit
anchors.fill: parent
- anchors.centerIn: parent
scale: 1
opacity: 0.7
z: 0
@@ -40,9 +59,8 @@ Item { source: "./assets/Ellipse 1.svg"
sourceSize.width: width
sourceSize.height: width
- anchors.fill: parent
- anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
+ anchors.fill: parent
scale: 1
opacity: 0.7
z: 1
@@ -52,49 +70,81 @@ Item { id: canvas
anchors.fill: parent
antialiasing: true
- property real degree: 0
-
- onDegreeChanged: requestPaint()
onPaint: {
- var ctx = getContext("2d")
- var center = Qt.point(width / 2, height / 2)
- var side = Math.min(width, height)
- var radius = (side - side * 0.20) / 2
- var startAngle = Math.PI * 3 / 4
- var fullAngle = Math.PI * 3 / 2
- var progressAngle = startAngle + (degree / 270) * fullAngle
-
- ctx.reset()
- ctx.lineCap = 'round'
-
- ctx.lineWidth = side * 0.1
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, progressAngle)
- ctx.strokeStyle = secondaryColor
- ctx.stroke()
-
- ctx.lineWidth = 20
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, progressAngle)
- ctx.strokeStyle = primaryColor
- ctx.stroke()
-
- // draw tick marks
- ctx.lineWidth = 10
- ctx.strokeStyle = '#FFFFFF'
- ctx.beginPath()
- var tickCount = 2; // Number of tick marks
- for (var i = 0; i < tickCount; i++) {
- var angle = startAngle + (i / (tickCount - 1)) * (progressAngle - startAngle)
- var x1 = center.x + radius * Math.cos(angle)
- var y1 = center.y + radius * Math.sin(angle)
- var x2 = center.x + (radius - 20) * Math.cos(angle)
- var y2 = center.y + (radius - 20) * Math.sin(angle)
- ctx.moveTo(x1, y1)
- ctx.lineTo(x2, y2)
+ var ctx = getContext("2d");
+ var center = Qt.point(width / 2, height / 2);
+
+ ctx.reset();
+ ctx.lineCap = 'round';
+
+ drawBackground(ctx, center);
+ drawProgress(ctx, center, value);
+ drawTicks(ctx, center);
+ drawProgressTick(ctx, center, value);
+ }
+
+ function drawBackground(ctx, center) {
+ ctx.lineWidth = gaugeRadius * 0.1;
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, gaugeRadius, startAngle, startAngle + fullAngle);
+ ctx.strokeStyle = secondaryColor;
+ ctx.stroke();
+ }
+
+ function drawProgress(ctx, center, progress) {
+ ctx.lineWidth = 20;
+
+ var gradient = ctx.createLinearGradient(
+ center.x - gaugeRadius, center.y,
+ center.x + gaugeRadius, center.y
+ );
+
+ gradient.addColorStop(0.0, "#00FF00");
+ //gradient.addColorStop(0.3, primaryColor);
+ gradient.addColorStop(0.4, "#FFD700");
+ gradient.addColorStop(1, "#FF0000");
+
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, gaugeRadius, startAngle, startAngle + (progress / (maxValue - minValue)) * fullAngle);
+ ctx.strokeStyle = gradient;
+ ctx.stroke();
+ }
+
+ function drawTicks(ctx, center) {
+ ctx.lineWidth = tickLength / 2;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
+
+ const tickCount = 10; // Adjust the number of ticks as needed
+
+ for (let i = 0; i <= tickCount; i++) {
+ const angle = startAngle + (i / tickCount) * fullAngle;
+ const x1 = center.x + gaugeRadius * Math.cos(angle);
+ const y1 = center.y + gaugeRadius * Math.sin(angle);
+ const x2 = center.x + (gaugeRadius - tickLength) * Math.cos(angle);
+ const y2 = center.y + (gaugeRadius - tickLength) * Math.sin(angle);
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
}
- ctx.stroke()
+
+ ctx.stroke();
+ }
+
+ function drawProgressTick(ctx, center, progress) {
+ ctx.lineWidth = tickLength * 1.5;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
+
+ const progressAngle = startAngle + (progress / (maxValue - minValue)) * 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();
}
}
@@ -111,7 +161,6 @@ Item { id: gaugeUnit
anchors.top: gaugeText.bottom
anchors.horizontalCenter: gaugeText.horizontalCenter
-
text: unit
font.pixelSize: 18
font.bold: true
@@ -125,41 +174,51 @@ Item { onValueChanged: updateGaugeValue(value)
function updateGaugeValue(value) {
- canvas.degree = value * 270
- gaugeText.text = (value * (maxValue - minValue) + minValue).toFixed(0)
- }
+ canvas.requestPaint(); // Request a repaint to reflect changes.
+ gaugeText.text = (value).toFixed(0); // Display the current value directly.
+ rpmValueChanged(value); // Emit the signal with the current value.
+ }
- MouseArea {
- anchors.fill: parent
- hoverEnabled: true
+ MouseArea {
+ id: dragArea
+ anchors.fill: parent
- property bool isDragging: false
- property real initialValue: 0
+ property bool isDragging: false
- onEntered: cursorShape = Qt.PointingHandCursor
- onPressed: {
- isDragging = true
- initialValue = root.value
- }
- onReleased: isDragging = false
+ onEntered: cursorShape = Qt.PointingHandCursor
- onMouseXChanged: updateDragValue(mouse.x, mouse.y)
- onMouseYChanged: updateDragValue(mouse.x, mouse.y)
+ onPressed: {
+ isDragging = true;
+ updateDragValue(mouseX, mouseY); // Update immediately on press.
+ }
+
+ onReleased: isDragging = false
- function updateDragValue(x, y) {
- if (!isDragging) return
+ onPositionChanged:
+ if (isDragging) {
+ updateDragValue(mouseX, mouseY); // Use formal parameters instead of injected ones.
+ }
- var centerX = width / 2
- var centerY = height / 2
- var dx = x - centerX
- var dy = centerY - y // Note: y-axis is inverted
- var angle = Math.atan2(dy, dx) * (180 / Math.PI)
+ function updateDragValue(x, y) {
+ const centerX = width / 2;
+ const centerY = height / 2;
- // Convert angle to gauge value (0 to 1)
- var gaugeValue = (angle + 135) / 270 // Adjust based on your gauge's start angle
- gaugeValue = Math.max(0, Math.min(gaugeValue, 1)) // Clamp value
+ // Calculate angle from the center to the mouse position.
+ const dx = x - centerX;
+ const dy = centerY - y; // Note that y-axis is inverted in QML.
+ const angle = Math.atan2(dy, dx);
- root.value = gaugeValue
- }
- }
+ // Normalize angle to [startAngle .. startAngle + fullAngle]
+ let normalizedAngle = angle < startAngle ? angle + Math.PI * 2 : angle;
+
+ // Calculate the normalized value based on the angle.
+ let normalizedValue = ((normalizedAngle - startAngle) / fullAngle) * (maxValue - minValue);
+
+ // Clamp value within min and max range.
+ normalizedValue = Math.max(minValue, Math.min(maxValue, normalizedValue));
+
+ // Update the root value.
+ root.value = normalizedValue;
+ }
+ }
}
diff --git a/QMLWidgets/Full_Gauge/SpeedGauge.qml b/QMLWidgets/Full_Gauge/SpeedGauge.qml index 02531b7..60d7525 100644 --- a/QMLWidgets/Full_Gauge/SpeedGauge.qml +++ b/QMLWidgets/Full_Gauge/SpeedGauge.qml @@ -2,8 +2,8 @@ import QtQuick 2.9 Item {
id: root
- width: 400
- height: 400
+ width: 300
+ height: 300
property real value: 0
property real minValue: 0
@@ -19,8 +19,11 @@ Item { property real gaugeRadius: 0
property real tickLength: 0
+ signal speedValueChanged(int value)
+
Component.onCompleted: {
calculateGeometry();
+ updateGaugeValue(value); // Initialize the gauge display
}
onWidthChanged: calculateGeometry()
@@ -29,7 +32,7 @@ Item { function calculateGeometry() {
const side = Math.min(width, height);
gaugeRadius = (side - side * 0.20) / 2;
- tickLength = gaugeRadius * 0.05;
+ tickLength = gaugeRadius * 0.1;
}
Rectangle {
@@ -67,9 +70,6 @@ Item { id: canvas
anchors.fill: parent
antialiasing: true
- property real degree: 0
-
- onDegreeChanged: requestPaint()
onPaint: {
var ctx = getContext("2d");
@@ -79,9 +79,9 @@ Item { ctx.lineCap = 'round';
drawBackground(ctx, center);
- drawProgress(ctx, center, degree);
+ drawProgress(ctx, center, value);
drawTicks(ctx, center);
- drawProgressTick(ctx, center, degree);
+ drawProgressTick(ctx, center, value);
}
function drawBackground(ctx, center) {
@@ -95,60 +95,56 @@ 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)
+ center.x - gaugeRadius, center.y,
+ center.x + gaugeRadius, center.y
);
- // 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
+ gradient.addColorStop(0.0, "#00FF00");
+ //gradient.addColorStop(0.3, primaryColor);
+ gradient.addColorStop(0.4, "#FFD700");
+ gradient.addColorStop(1, "#FF0000");
ctx.beginPath();
- ctx.arc(center.x, center.y, gaugeRadius, startAngle, startAngle + (progress / 270) * fullAngle);
-
- // Apply the gradient to the stroke style
+ ctx.arc(center.x, center.y, gaugeRadius, startAngle, startAngle + (progress / (maxValue - minValue)) * fullAngle);
ctx.strokeStyle = gradient;
ctx.stroke();
}
function drawTicks(ctx, center) {
- ctx.lineWidth = tickLength * 2
- ctx.strokeStyle = '#FFFFFF'
- ctx.beginPath()
- const tickCount = 2
- for (let i = 0; i < tickCount; i++) {
- const angle = startAngle + (i / (tickCount - 1)) * fullAngle
- const x1 = center.x + gaugeRadius * Math.cos(angle)
- const y1 = center.y + gaugeRadius * Math.sin(angle)
- const x2 = center.x + (gaugeRadius - tickLength) * Math.cos(angle)
- const y2 = center.y + (gaugeRadius - tickLength) * Math.sin(angle)
- ctx.moveTo(x1, y1)
- ctx.lineTo(x2, y2)
+ ctx.lineWidth = tickLength / 2;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
+
+ const tickCount = 10; // Adjust the number of ticks as needed
+
+ for (let i = 0; i <= tickCount; i++) {
+ const angle = startAngle + (i / tickCount) * fullAngle;
+ const x1 = center.x + gaugeRadius * Math.cos(angle);
+ const y1 = center.y + gaugeRadius * Math.sin(angle);
+ const x2 = center.x + (gaugeRadius - tickLength) * Math.cos(angle);
+ const y2 = center.y + (gaugeRadius - tickLength) * Math.sin(angle);
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
}
+
ctx.stroke();
}
function drawProgressTick(ctx, center, progress) {
+ ctx.lineWidth = tickLength * 1.5;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
- 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)
+ const progressAngle = startAngle + (progress / (maxValue - minValue)) * 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()
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
}
}
@@ -156,7 +152,7 @@ Item { id: gaugeText
anchors.centerIn: parent
text: "0"
- font.pixelSize: 0.2 * Math.min(root.width, root.height)
+ font.pixelSize: 0.3 * Math.min(root.width, root.height)
font.bold: true
color: "#FFFFFF"
}
@@ -178,42 +174,51 @@ Item { onValueChanged: updateGaugeValue(value)
function updateGaugeValue(value) {
- canvas.degree = value * 270
- gaugeText.text = (value * (maxValue - minValue) + minValue).toFixed(0)
- }
-
- MouseArea {
- id: dragArea
- anchors.fill: parent
- hoverEnabled: true
-
- property bool isDragging: false
- property real initialValue: 0
-
- onEntered: cursorShape = Qt.PointingHandCursor
- onPressed: {
- isDragging = true
- initialValue = root.value
- }
- onReleased: isDragging = false
-
- onMouseXChanged: updateDragValue(mouse.x, mouse.y)
- onMouseYChanged: updateDragValue(mouse.x, mouse.y)
-
- function updateDragValue(x, y) {
- if (!isDragging) return
-
- const centerX = width / 2
- const centerY = height / 2
- const dx = x - centerX
- const dy = centerY - y // Note: y-axis is inverted
- const angle = Math.atan2(dy, dx) * (180 / Math.PI)
-
- // Convert angle to gauge value (0 to 1)
- let gaugeValue = (angle + 135) / 270
- gaugeValue = Math.max(0, Math.min(gaugeValue, 1)) // Clamp value
-
- root.value = gaugeValue
- }
- }
-}
+ canvas.requestPaint(); // Request a repaint to reflect changes.
+ gaugeText.text = (value).toFixed(0); // Display the current value directly.
+ speedValueChanged(value); // Emit the signal with the current value.
+ }
+
+ MouseArea {
+ id: dragArea
+ anchors.fill: parent
+
+ property bool isDragging: false
+
+ onEntered: cursorShape = Qt.PointingHandCursor
+
+ onPressed: {
+ isDragging = true;
+ updateDragValue(mouseX, mouseY); // Update immediately on press.
+ }
+
+ onReleased: isDragging = false
+
+ onPositionChanged:
+ if (isDragging) {
+ updateDragValue(mouseX, mouseY); // Use formal parameters instead of injected ones.
+ }
+
+ function updateDragValue(x, y) {
+ const centerX = width / 2;
+ const centerY = height / 2;
+
+ // Calculate angle from the center to the mouse position.
+ const dx = x - centerX;
+ const dy = centerY - y; // Note that y-axis is inverted in QML.
+ const angle = Math.atan2(dy, dx);
+
+ // Normalize angle to [startAngle .. startAngle + fullAngle]
+ let normalizedAngle = angle < startAngle ? angle + Math.PI * 2 : angle;
+
+ // Calculate the normalized value based on the angle.
+ let normalizedValue = ((normalizedAngle - startAngle) / fullAngle) * (maxValue - minValue);
+
+ // Clamp value within min and max range.
+ normalizedValue = Math.max(minValue, Math.min(maxValue, normalizedValue));
+
+ // Update the root value.
+ root.value = normalizedValue;
+ }
+ }
+}
\ No newline at end of file diff --git a/QMLWidgets/Half_Gauge/CoolantGauge.qml b/QMLWidgets/Half_Gauge/CoolantGauge.qml index 634647d..fe402de 100644 --- a/QMLWidgets/Half_Gauge/CoolantGauge.qml +++ b/QMLWidgets/Half_Gauge/CoolantGauge.qml @@ -13,8 +13,11 @@ Item { property color primaryColor: "#16CCBA"
property color secondaryColor: "#00000000"
- property int animationDuration: 500
- property real startAngle: 0
+ property int animationDuration: 1000
+ property real startAngle: Math.PI * 5 / 4
+ property real fullAngle: Math.PI * 1 / 2
+
+ signal coolantTempValueChanged(int value)
Rectangle {
anchors.fill: parent
@@ -26,51 +29,66 @@ Item { id: canvas
anchors.fill: parent
antialiasing: true
- property real degree: 0
-
- onDegreeChanged: requestPaint()
onPaint: {
- var ctx = getContext("2d")
- 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 * 5 / 4
- var fullAngle = Math.PI * 1 / 2
- var progressAngle = startAngle + (degree / 270) * fullAngle
-
- ctx.reset()
- ctx.lineCap = 'round'
-
- // background arc
- ctx.lineWidth = 25
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, startAngle + fullAngle)
- ctx.strokeStyle = '#000000'
- ctx.stroke()
-
- // fill arc
- ctx.lineWidth = 15
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, progressAngle)
- ctx.strokeStyle = primaryColor
- ctx.stroke()
-
- // draw tick marks
- ctx.lineWidth = 5
- ctx.strokeStyle = '#FFFFFF'
- ctx.beginPath()
- var tickCount = 2; // Number of tick marks
- for (var i = 0; i < tickCount; i++) {
- var angle = startAngle + (i / (tickCount - 1)) * (progressAngle - startAngle)
- var x1 = center.x + radius * Math.cos(angle)
- var y1 = center.y + radius * Math.sin(angle)
- var x2 = center.x + (radius - 10) * Math.cos(angle)
- var y2 = center.y + (radius - 10) * Math.sin(angle)
- ctx.moveTo(x1, y1)
- ctx.lineTo(x2, y2)
+ var ctx = getContext("2d");
+ var center = Qt.point(width / 2, height / 2);
+ var side = Math.min(width, height);
+ var radius = (side - side * 0.25) / 2;
+ var progressAngle = startAngle + (value / (maxValue - minValue)) * fullAngle;
+
+ ctx.reset();
+ ctx.lineCap = 'round';
+
+ // Background arc
+ ctx.lineWidth = 25;
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, radius, startAngle, startAngle + fullAngle);
+ ctx.strokeStyle = '#000000';
+ ctx.stroke();
+
+ // Fill arc
+ ctx.lineWidth = 15;
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, radius, startAngle, progressAngle);
+ ctx.strokeStyle = primaryColor;
+ ctx.stroke();
+
+ // Draw tick marks
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
+ const tickCount = 2; // Adjust the number of ticks as needed
+
+ for (let i = 0; i <= tickCount; i++) {
+ const angle = startAngle + (i / tickCount) * fullAngle;
+ const x1 = center.x + radius * Math.cos(angle);
+ const y1 = center.y + radius * Math.sin(angle);
+ const x2 = center.x + (radius - 10) * Math.cos(angle);
+ const y2 = center.y + (radius - 10) * Math.sin(angle);
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
}
- ctx.stroke()
+
+ ctx.stroke();
+
+ // Draw progress tick mark
+ drawProgressTick(ctx, center, progressAngle, radius);
+ }
+
+ function drawProgressTick(ctx, center, angle, radius) {
+ ctx.lineWidth = 8; // Thickness of the progress tick mark
+ ctx.strokeStyle = '#FFFFFF'; // Color of the progress tick mark
+ ctx.beginPath();
+
+ const x1 = center.x + radius * Math.cos(angle);
+ const y1 = center.y + radius * Math.sin(angle);
+ const x2 = center.x + (radius - 15) * Math.cos(angle); // Adjust length as needed
+ const y2 = center.y + (radius - 15) * Math.sin(angle);
+
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
}
}
@@ -84,7 +102,7 @@ Item { }
Text {
- id: gaugePercentage
+ id: gaugeUnit
anchors.verticalCenter: gaugeText.verticalCenter
anchors.left: gaugeText.right
text: unit
@@ -99,52 +117,61 @@ Item { anchors.horizontalCenter: gaugeText.horizontalCenter
width: 0.15 * Math.min(root.width, root.height)
fillMode: Image.PreserveAspectFit
- // antialiasing: true
antialiasing: true
}
Behavior on value {
NumberAnimation { duration: animationDuration }
}
-
+
onValueChanged: updateGaugeValue(value)
function updateGaugeValue(value) {
- canvas.degree = value * 270
- gaugeText.text = (value * (maxValue - minValue) + minValue).toFixed(0)
+ canvas.requestPaint(); // Request a repaint to reflect changes.
+ gaugeText.text = value.toFixed(0); // Display the current value directly.
+ coolantTempValueChanged(value); // Emit the signal with the current value.
}
- MouseArea {
- anchors.fill: parent
- hoverEnabled: true
+ MouseArea {
+ id: dragArea
+ anchors.fill: parent
- property bool isDragging: false
- property real initialValue: 0
+ property bool isDragging: false
- onEntered: cursorShape = Qt.PointingHandCursor
- onPressed: {
- isDragging = true
- initialValue = root.value
- }
- onReleased: isDragging = false
+ onEntered: cursorShape = Qt.PointingHandCursor
- onMouseXChanged: updateDragValue(mouse.x, mouse.y)
- onMouseYChanged: updateDragValue(mouse.x, mouse.y)
+ onPressed: {
+ isDragging = true;
+ updateDragValue(mouseX, mouseY); // Update immediately on press.
+ }
+
+ onReleased: isDragging = false
- function updateDragValue(x, y) {
- if (!isDragging) return
+ onPositionChanged:
+ if (isDragging) {
+ updateDragValue(mouseX, mouseY); // Use formal parameters instead of injected ones.
+ }
- var centerX = width / 2
- var centerY = height / 2
- var dx = x - centerX
- var dy = centerY - y // Note: y-axis is inverted
- var angle = Math.atan2(dy, dx) * (180 / Math.PI)
+ function updateDragValue(x, y) {
+ const centerX = width / 2;
+ const centerY = height / 2;
- // Convert angle to gauge value (0 to 1)
- var gaugeValue = (angle + 135) / 270; // Adjust based on your gauge's start angle
- gaugeValue = Math.max(0, Math.min(gaugeValue, 1)); // Clamp value
+ // Calculate angle from the center to the mouse position.
+ const dx = x - centerX;
+ const dy = centerY - y; // Note that y-axis is inverted in QML.
+ const angle = Math.atan2(dy, dx);
- root.value = gaugeValue;
- }
- }
-}
+ // Normalize angle to [startAngle .. startAngle + fullAngle]
+ let normalizedAngle = angle < startAngle ? angle + Math.PI * 2 : angle;
+
+ // Calculate the normalized value based on the angle.
+ let normalizedValue = ((normalizedAngle - startAngle) / fullAngle) * (maxValue - minValue);
+
+ // Clamp value within min and max range.
+ normalizedValue = Math.max(minValue, Math.min(maxValue, normalizedValue));
+
+ // Update the root value.
+ root.value = normalizedValue;
+ }
+ }
+}
\ No newline at end of file diff --git a/QMLWidgets/Half_Gauge/FuelGauge.qml b/QMLWidgets/Half_Gauge/FuelGauge.qml index f0ea7d0..4a768a0 100644 --- a/QMLWidgets/Half_Gauge/FuelGauge.qml +++ b/QMLWidgets/Half_Gauge/FuelGauge.qml @@ -13,10 +13,11 @@ Item { property color primaryColor: "#16CCBA"
property color secondaryColor: "#00000000"
- property int animationDuration: 500
- property real startAngle: 0
+ property int animationDuration: 1000
+ property real startAngle: Math.PI * 5 / 4
+ property real fullAngle: Math.PI * 1 / 2
- property var exposedFunction: updateGaugeUnit
+ signal fuelLevelValueChanged(int value)
Rectangle {
anchors.fill: parent
@@ -28,51 +29,66 @@ Item { id: canvas
anchors.fill: parent
antialiasing: true
- property real degree: 0
-
- onDegreeChanged: requestPaint()
onPaint: {
- var ctx = getContext("2d")
- 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 * 5 / 4
- var fullAngle = Math.PI * 1 / 2
- var progressAngle = startAngle + (degree / 270) * fullAngle
-
- ctx.reset()
- ctx.lineCap = 'round'
-
- // background arc
- ctx.lineWidth = 25
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, startAngle + fullAngle)
- ctx.strokeStyle = '#000000'
- ctx.stroke()
-
- // fill arc
- ctx.lineWidth = 15
- ctx.beginPath()
- ctx.arc(center.x, center.y, radius, startAngle, progressAngle)
- ctx.strokeStyle = primaryColor
- ctx.stroke()
-
- // draw tick marks
- ctx.lineWidth = 5
- ctx.strokeStyle = '#FFFFFF'
- ctx.beginPath()
- var tickCount = 2; // Number of tick marks
- for (var i = 0; i < tickCount; i++) {
- var angle = startAngle + (i / (tickCount - 1)) * (progressAngle - startAngle)
- var x1 = center.x + radius * Math.cos(angle)
- var y1 = center.y + radius * Math.sin(angle)
- var x2 = center.x + (radius - 10) * Math.cos(angle)
- var y2 = center.y + (radius - 10) * Math.sin(angle)
- ctx.moveTo(x1, y1)
- ctx.lineTo(x2, y2)
+ var ctx = getContext("2d");
+ var center = Qt.point(width / 2, height / 2);
+ var side = Math.min(width, height);
+ var radius = (side - side * 0.25) / 2;
+ var progressAngle = startAngle + (value / (maxValue - minValue)) * fullAngle;
+
+ ctx.reset();
+ ctx.lineCap = 'round';
+
+ // Background arc
+ ctx.lineWidth = 25;
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, radius, startAngle, startAngle + fullAngle);
+ ctx.strokeStyle = '#000000';
+ ctx.stroke();
+
+ // Fill arc
+ ctx.lineWidth = 15;
+ ctx.beginPath();
+ ctx.arc(center.x, center.y, radius, startAngle, progressAngle);
+ ctx.strokeStyle = primaryColor;
+ ctx.stroke();
+
+ // Draw tick marks
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = '#FFFFFF';
+ ctx.beginPath();
+ const tickCount = 2; // Adjust the number of ticks as needed
+
+ for (let i = 0; i <= tickCount; i++) {
+ const angle = startAngle + (i / tickCount) * fullAngle;
+ const x1 = center.x + radius * Math.cos(angle);
+ const y1 = center.y + radius * Math.sin(angle);
+ const x2 = center.x + (radius - 10) * Math.cos(angle);
+ const y2 = center.y + (radius - 10) * Math.sin(angle);
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
}
- ctx.stroke()
+
+ ctx.stroke();
+
+ // Draw progress tick mark
+ drawProgressTick(ctx, center, progressAngle, radius);
+ }
+
+ function drawProgressTick(ctx, center, angle, radius) {
+ ctx.lineWidth = 8; // Thickness of the progress tick mark
+ ctx.strokeStyle = '#FFFFFF'; // Color of the progress tick mark
+ ctx.beginPath();
+
+ const x1 = center.x + radius * Math.cos(angle);
+ const y1 = center.y + radius * Math.sin(angle);
+ const x2 = center.x + (radius - 15) * Math.cos(angle); // Adjust length as needed
+ const y2 = center.y + (radius - 15) * Math.sin(angle);
+
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
}
}
@@ -87,8 +103,6 @@ Item { Text {
id: gaugePercentage
- // anchor this to the right of the gaugeText such that their baseline is aligned
-
anchors.verticalCenter: gaugeText.verticalCenter
anchors.left: gaugeText.right
text: unit
@@ -103,56 +117,61 @@ Item { anchors.horizontalCenter: gaugeText.horizontalCenter
width: 0.15 * Math.min(root.width, root.height)
fillMode: Image.PreserveAspectFit
- // antialiasing: true
antialiasing: true
}
Behavior on value {
NumberAnimation { duration: animationDuration }
}
-
+
onValueChanged: updateGaugeValue(value)
function updateGaugeValue(value) {
- canvas.degree = value * 270
- gaugeText.text = (value * (maxValue - minValue) + minValue).toFixed(0)
+ canvas.requestPaint(); // Request a repaint to reflect changes.
+ gaugeText.text = value.toFixed(0); // Display the current value directly.
+ fuelLevelValueChanged(value); // Emit the signal with the current value.
}
- function updateGaugeUnit() {
- gaugeUnit.text = unit
- }
+ MouseArea {
+ id: dragArea
+ anchors.fill: parent
- MouseArea {
- anchors.fill: parent
- hoverEnabled: true
+ property bool isDragging: false
- property bool isDragging: false
- property real initialValue: 0
+ onEntered: cursorShape = Qt.PointingHandCursor
- onEntered: cursorShape = Qt.PointingHandCursor
- onPressed: {
- isDragging = true
- initialValue = root.value
- }
- onReleased: isDragging = false
+ onPressed: {
+ isDragging = true;
+ updateDragValue(mouseX, mouseY); // Update immediately on press.
+ }
+
+ onReleased: isDragging = false
- onMouseXChanged: updateDragValue(mouse.x, mouse.y)
- onMouseYChanged: updateDragValue(mouse.x, mouse.y)
+ onPositionChanged:
+ if (isDragging) {
+ updateDragValue(mouseX, mouseY); // Use formal parameters instead of injected ones.
+ }
- function updateDragValue(x, y) {
- if (!isDragging) return
+ function updateDragValue(x, y) {
+ const centerX = width / 2;
+ const centerY = height / 2;
- var centerX = width / 2
- var centerY = height / 2
- var dx = x - centerX
- var dy = centerY - y // Note: y-axis is inverted
- var angle = Math.atan2(dy, dx) * (180 / Math.PI)
+ // Calculate angle from the center to the mouse position.
+ const dx = x - centerX;
+ const dy = centerY - y; // Note that y-axis is inverted in QML.
+ const angle = Math.atan2(dy, dx);
- // Convert angle to gauge value (0 to 1)
- var gaugeValue = (angle + 135) / 270; // Adjust based on your gauge's start angle
- gaugeValue = Math.max(0, Math.min(gaugeValue, 1)); // Clamp value
+ // Normalize angle to [startAngle .. startAngle + fullAngle]
+ let normalizedAngle = angle < startAngle ? angle + Math.PI * 2 : angle;
- root.value = gaugeValue;
- }
- }
-}
+ // Calculate the normalized value based on the angle.
+ let normalizedValue = ((normalizedAngle - startAngle) / fullAngle) * (maxValue - minValue);
+
+ // Clamp value within min and max range.
+ normalizedValue = Math.max(minValue, Math.min(maxValue, normalizedValue));
+
+ // Update the root value.
+ root.value = normalizedValue;
+ }
+ }
+}
\ No newline at end of file diff --git a/QMLWidgets/Temp_Tumbler/TempTumbler.qml b/QMLWidgets/Temp_Tumbler/TempTumbler.qml index 612d9a3..351f352 100644 --- a/QMLWidgets/Temp_Tumbler/TempTumbler.qml +++ b/QMLWidgets/Temp_Tumbler/TempTumbler.qml @@ -5,19 +5,24 @@ import QtQuick.Controls 2.2 Rectangle { width: frame.implicitWidth height: frame.implicitHeight - - // save colors in variables + + // 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 + // 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 - + color: "#041F2B" + // Remove rectangular border + border.color: "#041F2B" + border.width: 0 + anchors.fill: parent + anchors.margins: -5 + signal valueChanged(int newValue) FontMetrics { @@ -40,32 +45,31 @@ Rectangle { Frame { id: frame - padding: 0 + padding: 10 anchors.centerIn: parent anchors.fill: parent Rectangle { anchors.fill: parent - color: backgroundColor - radius: 10 + color: "#041F2B" + radius: width / 4 } Column { - spacing: 10 + spacing: 5 anchors.fill: parent - anchors.horizontalCenter: parent.horizontalCenter - anchors.margins: 10 + anchors.margins: 2 Button { width: parent.width - height: parent.height / 6 + height: parent.height * 1 / 4 - Rectangle { + background : Rectangle { width: parent.width height: parent.height color: buttonColor - radius: 10 + radius: width / 4 Image { source: iconUp @@ -77,11 +81,10 @@ Rectangle { } } onClicked: { - // if we are at the top of the list, set the index to the last element + // 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 { + } else { valueTumbler.currentIndex -= 1; } } @@ -90,8 +93,10 @@ Rectangle { Tumbler { id: valueTumbler anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - height: parent.height / 2 + height: parent.height * 2 / 4 + model: ListModel { ListElement { number: 16 } ListElement { number: 17 } @@ -118,23 +123,26 @@ Rectangle { delegate: delegateComponent - Rectangle { + background : Rectangle { width: parent.width height: parent.height - color: background_alt - radius: 10 + color: backgroundColor + border.color: buttonColor + border.width: 2 + radius: width / 4 } } Button { + id: buttonDown width: parent.width - height: parent.height / 6 + height: parent.height * 1 / 4 - Rectangle { + background : Rectangle { width: parent.width height: parent.height color: buttonColor - radius: 10 + radius: width / 4 Image { source: iconDown @@ -148,8 +156,7 @@ Rectangle { onClicked: { if (valueTumbler.currentIndex == 16) { valueTumbler.currentIndex = 0; - } - else { + } else { valueTumbler.currentIndex += 1; } } diff --git a/Scripts/record_playback.py b/Scripts/record_playback.py index 0e631ad..4d067f1 100644 --- a/Scripts/record_playback.py +++ b/Scripts/record_playback.py @@ -34,7 +34,6 @@ class CAN_playback(QThread): def __init__(self, interface='vcan0'): super(CAN_playback, self).__init__() self._running = False - self.console_mode = False self.interface = interface self.bus = can.interface.Bus(interface='socketcan', channel=self.interface, bitrate=500000) @@ -57,7 +56,8 @@ class CAN_playback(QThread): for msg in messages: file.write(f"{msg.timestamp},{msg.arbitration_id},{msg.dlc},{','.join(map(lambda b: f'0x{b:02x}', msg.data))}\n") - def playback_messages(self): + def run(self): + """Override run method to handle playback messages.""" if os.path.exists(self.output_file): messages = [] with open(self.output_file, 'r') as file: @@ -75,16 +75,41 @@ class CAN_playback(QThread): messages.append(msg) self.replay_messages(messages) - def stop(self): + def start_playback(self): + """Start playback if not already running.""" + if not self._running: + self._running = True + self.start() # Start the QThread + + + def stop_playback(self): + """Stop playback.""" + if self._running: + self.reset() + + # Wait for thread to finish before shutting down the bus + self.wait(1000) + + self.finished.emit() + + def reset(self): + """Reset the playback.""" self._running = False - if self.bus is not None: - self.bus.shutdown() - self.finished.emit() + self.speedUpdate.emit(0) + self.gearUpdate.emit("N") + self.engineSpeedUpdate.emit(0) + self.throttleUpdate.emit(0) + self.indicatorUpdate.emit("HazardOff") def replay_messages(self, messages): - self._running = True + """Replay CAN messages.""" + # self._running = True start_time = messages[0].timestamp + for msg in messages: + if not self._running: # Check if playback should stop + return + delay = msg.timestamp - start_time self.bus.send(msg) @@ -97,8 +122,6 @@ class CAN_playback(QThread): time.sleep(delay) start_time = msg.timestamp - if not self._running: - return def decode_message(self, message_name, data): message = self.db.get_message_by_name(message_name) @@ -178,29 +201,38 @@ def main(): console = Console() while True: - console.print("\n[bold]CAN Message Capture and Playback[/bold]") - console.print("1. Capture CAN messages") - console.print("2. Replay captured messages") - console.print("3. Exit") - - choice = Prompt.ask("Enter your choice", choices=['1', '2', '3']) - - if choice == '1': - messages = can_tool.capture_can_messages() - console.print(f"Captured {len(messages)} messages.") - can_tool.write_to_file(messages) - console.print(f"CAN messages written to {can_tool.output_file}") - elif choice == '2': - if os.path.exists(can_tool.output_file): - console.print("Replaying captured messages...") - can_tool.playback_messages() - console.print("Replay completed.") - else: - console.print(f"No captured messages found in {can_tool.output_file}") - + if can_tool._running: + console.print("Playback in progress. Please stop playback before capturing new messages.") + # ask for input 1 to stop playback + choice = Prompt.ask("Enter your choice", choices=['1']) + if choice == '1': + can_tool.stop_playback() + console.print("Playback stopped. Ready to capture new messages.") + continue else: - console.print("Exiting...") - break + console.print("\n[bold]CAN Message Capture and Playback[/bold]") + console.print("1. Capture CAN messages") + console.print("2. Replay captured messages") + console.print("3. Exit") + + choice = Prompt.ask("Enter your choice", choices=['1', '2', '3']) + + if choice == '1': + messages = can_tool.capture_can_messages() + console.print(f"Captured {len(messages)} messages.") + can_tool.write_to_file(messages) + console.print(f"CAN messages written to {can_tool.output_file}") + elif choice == '2': + if os.path.exists(can_tool.output_file): + console.print("Replaying captured messages...") + can_tool.start_playback() + console.print("Replay completed.") + else: + console.print(f"No captured messages found in {can_tool.output_file}") + + else: + console.print("Exiting...") + break if __name__ == "__main__": main() diff --git a/Widgets/Dashboard.py b/Widgets/Dashboard.py index 9df290f..b8dfc92 100644 --- a/Widgets/Dashboard.py +++ b/Widgets/Dashboard.py @@ -57,6 +57,7 @@ class Dashboard(Base, Form): Dashboard_tiles = (self.DB_IC_Tile, self.DB_HVAC_Tile, self.DB_Steering_Tile, + self.DB_Keypad_Tile, self.DB_Settings_Tile) DashboardTiles = QtWidgets.QButtonGroup(self) @@ -73,6 +74,12 @@ class Dashboard(Base, Form): self.DB_Steering_Tile.setEnabled(False) self.DB_Steering_Tile.setStyleSheet("background-color : darkGray; color: gray") enabled = False + if tile == self.DB_Keypad_Tile and not config.keypad_enabled(): + self.DB_Keypad_Tile.setEnabled(False) + # hide the keypad tile + self.DB_Keypad_Tile.hide() + self.DB_Keypad_Tile.setStyleSheet("background-color : darkGray; color: gray") + enabled = False self.set_icon(tile, 90) DashboardTiles.addButton(tile) @@ -120,8 +127,10 @@ class Dashboard(Base, Form): self.parent().setCurrentIndex(2) elif tile == self.DB_Steering_Tile: self.parent().setCurrentIndex(3) - elif tile == self.DB_Settings_Tile: + elif tile == self.DB_Keypad_Tile: self.parent().setCurrentIndex(4) + elif tile == self.DB_Settings_Tile: + self.parent().setCurrentIndex(5) self.tileClickedSignal.emit() diff --git a/Widgets/HVACPage.py b/Widgets/HVACPage.py index 8371dfe..0a72866 100644 --- a/Widgets/HVACPage.py +++ b/Widgets/HVACPage.py @@ -6,11 +6,11 @@ import os import sys from PyQt6 import uic -from PyQt6.QtWidgets import QApplication, QFrame, QSlider, QPushButton, QWidget +from PyQt6.QtWidgets import QApplication, QFrame, QSlider, QWidget from PyQt6 import QtWidgets from PyQt6.QtQuickWidgets import QQuickWidget -from PyQt6.QtQuick import QQuickItem from PyQt6.QtCore import QUrl +from PyQt6.QtCore import QTimer current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -69,7 +69,6 @@ class HVACWidget(Base, Form): # Create left temperature tumbler self.LeftTempTumbler = TumblerWidget() - # Connect the left tumbler signal to the handler self.LeftTempTumbler.rootObject().valueChanged.connect(self.onLeftTempChanged) @@ -96,6 +95,14 @@ class HVACWidget(Base, Form): QSlider, "rightFanSpeed_slider") self.rightFanSpeed_slider.valueChanged.connect( self.rightFanSpeed_sliderChanged) + + # after 2 seconds reconnect the signals + QTimer.singleShot(500, self.reconnectSignals) + + # funcyion to reconnect the tumbler signals + def reconnectSignals(self): + self.LeftTempTumbler.rootObject().valueChanged.connect(self.onLeftTempChanged) + self.RightTempTumbler.rootObject().valueChanged.connect(self.onRightTempChanged) def changeTemperature(self, tumbler_widget, change): """Change tumbler value by incrementing or decrementing.""" diff --git a/Widgets/ICPage.py b/Widgets/ICPage.py index 0f44703..a298d2b 100644 --- a/Widgets/ICPage.py +++ b/Widgets/ICPage.py @@ -12,6 +12,7 @@ from PyQt6.QtGui import QIcon, QPixmap, QPainter from PyQt6.QtCore import QObject, pyqtSignal, QThread from PyQt6.QtWidgets import QWidget, QFrame, QDockWidget from PyQt6.QtQuickWidgets import QQuickWidget +from PyQt6.QtCore import QTimer import threading current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -65,6 +66,8 @@ def Gauge(gaugeType): gauge.setResizeMode(QQuickWidget.ResizeMode.SizeRootObjectToView) gauge.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) + + gauge.rootContext().setContextObject(gauge) return gauge @@ -139,7 +142,6 @@ class ICWidget(Base, Form): self.Speed_Gauge = Gauge("Speed") self.Frame_1.layout().replaceWidget(Speed_Gauge_Placeholder, self.Speed_Gauge) - self.Speed_slider.valueChanged.connect(self.update_Speed_gauge) self.Speed_slider.setMinimum(0) self.Speed_slider.setMaximum(240) @@ -148,7 +150,6 @@ class ICWidget(Base, Form): self.RPM_Gauge = Gauge("RPM") self.Frame_1.layout().replaceWidget(RPM_Gauge_Placeholder, self.RPM_Gauge) - self.RPM_slider.valueChanged.connect(self.update_RPM_monitor) self.RPM_slider.setMinimum(0) self.RPM_slider.setMaximum(8000) @@ -164,11 +165,6 @@ class ICWidget(Base, Form): 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.leftIndicatorBtn.setCheckable(True) self.rightIndicatorBtn.setCheckable(True) self.hazardBtn.setCheckable(True) @@ -190,6 +186,26 @@ class ICWidget(Base, Form): QtWidgets.QPushButton, "TirePressureBtn") self.TirePressureBtn.clicked.connect(self.toggle_TirePressureDock) + # after 2 seconds reconnect the signals + QTimer.singleShot(500, self.reconnectSignals) + + # hide Tirepressure dock by default + self.Hide_TirePressure(True) + + # function to reconnect all the gauge signals + def reconnectSignals(self): + self.Speed_Gauge.rootObject().speedValueChanged.connect(lambda value: self.update_Speed("gauge", value)) + self.Speed_slider.valueChanged.connect(lambda : self.update_Speed("slider", self.Speed_slider.value())) + + self.RPM_Gauge.rootObject().rpmValueChanged.connect(lambda value: self.update_RPM("gauge", value)) + self.RPM_slider.valueChanged.connect(lambda : self.update_RPM("slider", self.RPM_slider.value())) + + self.Coolant_Gauge.rootObject().coolantTempValueChanged.connect(lambda value: self.update_coolantTemp("gauge", value)) + self.coolantTemp_slider.valueChanged.connect(lambda : self.update_coolantTemp("slider", self.coolantTemp_slider.value())) + + self.Fuel_Gauge.rootObject().fuelLevelValueChanged.connect(lambda value: self.update_fuelLevel("gauge", value)) + self.fuelLevel_slider.valueChanged.connect(lambda : self.update_fuelLevel("slider", self.fuelLevel_slider.value())) + def toggle_TirePressureDock(self): if self.TirePressureBtn.isChecked(): self.Hide_TirePressure(True) @@ -233,58 +249,126 @@ class ICWidget(Base, Form): self.rightIndicatorBtn.setChecked(False) def set_Vehicle_Speed(self, speed): - self.Speed_slider.setValue(speed) + self.Speed_Gauge.rootObject().setProperty('value', speed) def set_Vehicle_RPM(self, rpm): - self.RPM_slider.setValue(rpm) + self.RPM_Gauge.rootObject().setProperty('value', rpm) - def update_Speed_gauge(self): + def update_Speed(self, source, value): """ - Updates the speed monitor with the current speed value. + Updates the speed value with the current value from either the gauge or the slider. + + Parameters: + value: The speed value to update. + source: A string indicating the source of the value ('gauge' or 'slider'). """ - speed = int(self.Speed_slider.value()) - speed = speed / 240 - self.Speed_Gauge.rootObject().setProperty('value', speed) + + speed = int(value) + + if source == 'gauge': + # Update slider to reflect the gauge's value + self.Speed_slider.blockSignals(True) + self.Speed_slider.setValue(speed) + print(speed) + self.Speed_slider.blockSignals(False) + + elif source == 'slider': + # Set animation duration to 0 for immediate update + self.Speed_Gauge.rootObject().setProperty('animationDuration', 0) + + # Update gauge to reflect the slider's value + self.Speed_Gauge.blockSignals(True) + self.Speed_Gauge.rootObject().setProperty('value', speed) + self.Speed_Gauge.blockSignals(False) + + # Reset animation duration for smooth transitions + self.Speed_Gauge.rootObject().setProperty('animationDuration', 500) + + # Send updated speed to kuksa if simulator is not running if not self.simulator_running: try: self.kuksa_client.set(self.IC.speed, str(speed), 'value') except Exception as e: logging.error(f"Error sending values to kuksa {e}") - def update_RPM_monitor(self): + def update_RPM(self, source, value): """ - Updates the RPM monitor with the current RPM value. + Updates the RPM value with the current value from either the gauge or the slider. + + Parameters: + value: The RPM value to update. + source: A string indicating the source of the value ('gauge' or 'slider'). """ - rpm = int(self.RPM_slider.value()) - rpm = rpm / 8000 - self.RPM_Gauge.rootObject().setProperty('value', rpm) + + rpm = int(value) + + if source == 'gauge': + # Update slider to reflect the gauge's value + self.RPM_slider.blockSignals(True) + self.RPM_slider.setValue(int(rpm)) + self.RPM_slider.blockSignals(False) + + elif source == 'slider': + # Set animation duration to 0 for immediate update + self.RPM_Gauge.rootObject().setProperty('animationDuration', 0) + + # Update gauge to reflect the slider's value + self.RPM_Gauge.blockSignals(True) + self.RPM_Gauge.rootObject().setProperty('value', rpm) + self.RPM_Gauge.blockSignals(False) + + # Reset animation duration for smooth transitions + self.RPM_Gauge.rootObject().setProperty('animationDuration', 1000) + + # Send updated RPM to kuksa if simulator is not running if not self.simulator_running: try: self.kuksa_client.set(self.IC.engineRPM, str(rpm), 'value') except Exception as e: logging.error(f"Error sending values to kuksa {e}") - def update_coolantTemp_monitor(self): + def update_coolantTemp(self, source, value): """ - Updates the coolant temperature monitor with the current coolant temperature value. + Updates the coolant temperature with the current coolant temperature value from the gauge. or the slider. """ - coolantTemp = int(self.coolantTemp_slider.value()) - gaugeValue = coolantTemp / 100 - self.Coolant_Gauge.rootObject().setProperty('value', gaugeValue) + coolantTemp = int(value) + + if source == 'gauge': + # Update slider to reflect the gauge's value + self.coolantTemp_slider.blockSignals(True) + self.coolantTemp_slider.setValue(coolantTemp) + self.coolantTemp_slider.blockSignals(False) + elif source == 'slider': + # Update gauge to reflect the slider's value + self.Coolant_Gauge.rootObject().setProperty('animationDuration', 0) + self.Coolant_Gauge.blockSignals(True) + self.Coolant_Gauge.rootObject().setProperty('value', coolantTemp) + self.Coolant_Gauge.blockSignals(False) + self.Coolant_Gauge.rootObject().setProperty('animationDuration', 1000) try: self.kuksa_client.set( self.IC.coolantTemp, str(coolantTemp), 'value') except Exception as e: logging.error(f"Error sending values to kuksa {e}") - def update_fuelLevel_monitor(self): + def update_fuelLevel(self, source, value): """ - Updates the fuel level monitor with the current fuel level value. + Updates the fuel level with the current fuel level value from the gauge. or the slider. """ - fuelLevel = int(self.fuelLevel_slider.value()) - FuelGaugeLevel = fuelLevel / 100 - self.Fuel_Gauge.rootObject().setProperty('value', FuelGaugeLevel) - print(self.Fuel_Gauge.rootObject().property('value')) + fuelLevel = int(value) + + if source == 'gauge': + # Update slider to reflect the gauge's value + self.fuelLevel_slider.blockSignals(True) + self.fuelLevel_slider.setValue(fuelLevel) + self.fuelLevel_slider.blockSignals(False) + elif source == 'slider': + # Update gauge to reflect the slider's value + self.Fuel_Gauge.rootObject().setProperty('animationDuration', 0) + self.Fuel_Gauge.blockSignals(True) + self.Fuel_Gauge.rootObject().setProperty('value', fuelLevel) + self.Fuel_Gauge.blockSignals(False) + self.Fuel_Gauge.rootObject().setProperty('animationDuration', 1000) try: self.kuksa_client.set(self.IC.fuelLevel, str(fuelLevel)) except Exception as e: @@ -394,20 +478,23 @@ class ICWidget(Base, Form): 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() + # self.Playback.start() + print("Playback started") + + try: + if self.Playback is None: + self.Playback = CAN_playback() + except Exception as e: + logging.error(f"Error creating playback object {e}") + self.Script_toggle.showError() + return + + if not self.Playback.isRunning(): + self.Playback.start_playback() + else: + self.Playback_connections() # hide sliders from the layout, their space will be taken by the playback widgets self.Speed_slider.hide() self.RPM_slider.hide() @@ -415,12 +502,15 @@ class ICWidget(Base, Form): # set default values for coolent and fuel self.coolantTemp_slider.setValue(90) self.fuelLevel_slider.setValue(50) - - elif not self.Script_toggle.isChecked(): - self.Playback.stop() - self.thread.quit() - self.thread.wait() - + else: + # self.Playback.stop_and_join() + if self.Playback and self.Playback.isRunning: + self.Playback.stop_playback() + self.Playback.wait() + #self.Playback.finished.connect(self.Playback.deleteLater) + self.Playback = None + + print("Playback stopped") self.Speed_slider.show() self.RPM_slider.show() @@ -471,7 +561,7 @@ class ICWidget(Base, Form): self.RPM_slider.setValue(self.current_rpm) self.update_Speed_gauge() - self.update_RPM_monitor() + self.update_RPM_Gauge() def driveBtnClicked(self): gear_mapping = { diff --git a/Widgets/Keypad.py b/Widgets/Keypad.py index 264bb5d..158849e 100644 --- a/Widgets/Keypad.py +++ b/Widgets/Keypad.py @@ -1,10 +1,9 @@ import os import sys from PyQt6 import uic -from PyQt6.QtWidgets import QPushButton -from PyQt6.QtWidgets import QApplication, QWidget +from PyQt6.QtWidgets import QToolButton, QApplication, QWidget +from PyQt6.QtGui import QPixmap, QIcon import requests -from urllib.parse import urljoin current_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.dirname(current_dir)) @@ -12,30 +11,55 @@ sys.path.append(os.path.dirname(current_dir)) Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/Keypad.ui")) import res_rc +from extras import config class KeypadWidget(Base, Form): def __init__(self, parent=None): super(self.__class__, self).__init__(parent) self.setupUi(self) - self.host = "localhost" - self.port = 8080 - # Mapping of keys to API endpoints + # Load configuration + self.host, self.port = config.get_keypad_config() + + frame = self.findChild(QWidget, "frame") + + # Mapping of keys to API endpoints and button labels self.key_endpoints = { - "Key_1": "/cgi-bin/flutter.cgi", - "Key_2": "/cgi-bin/qt.cgi", - "Key_3": "/cgi-bin/momi.cgi", - "Key_4": "/cgi-bin/bomb.cgi", - "Key_5": "", # This key won't do anything + "Key_1": ("/cgi-bin/flutter.cgi", "Flutter Demo"), + "Key_2": ("/cgi-bin/qt.cgi", "Qt Demo"), + "Key_3": ("/cgi-bin/momi.cgi", "Momi Demo"), + "Key_4": ("/cgi-bin/bomb.cgi", "Bomb Demo") } - # Connect all keys to the same slot - for key_name in self.key_endpoints.keys(): - key_button = self.findChild(QPushButton, key_name) + # Connect all keys to the same slot and configure buttons + for key_name, (endpoint, label) in self.key_endpoints.items(): + key_button = self.findChild(QToolButton, key_name) + key_button.setObjectName(key_name) # Set button name + + # Set button label + key_button.setText(label) + # set font size and style based on height of the button + font = key_button.font() + font.setPointSize(int(key_button.height())) + font.setBold(True) + font.setItalic(True) + key_button.setFont(font) + + # place the label under the icon + # key_button.setIconSize(key_button.size()) + + + # Connect button click to API trigger key_button.clicked.connect(lambda _, x=key_name: self.trigger_api(x)) + # Hide unused keys based on configuration + keys_to_hide = config.get_keypad_keys_to_hide() + for key_name in keys_to_hide: + key_button = self.findChild(QToolButton, "Key_" + key_name) + key_button.hide() + def trigger_api(self, key_name): - endpoint = self.key_endpoints[key_name] + endpoint = self.key_endpoints[key_name][0] # Get the endpoint from the tuple if endpoint: url = f"http://{self.host}:{self.port}{endpoint}" try: @@ -51,4 +75,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = KeypadWidget() w.show() - sys.exit(app.exec()) + sys.exit(app.exec())
\ No newline at end of file diff --git a/assets/Images/Key_1.png b/assets/Images/Key_1.png Binary files differnew file mode 100644 index 0000000..25cd0d0 --- /dev/null +++ b/assets/Images/Key_1.png diff --git a/assets/Images/Key_2.png b/assets/Images/Key_2.png Binary files differnew file mode 100644 index 0000000..e69e6bd --- /dev/null +++ b/assets/Images/Key_2.png diff --git a/assets/Images/Key_3.png b/assets/Images/Key_3.png Binary files differnew file mode 100644 index 0000000..e72082d --- /dev/null +++ b/assets/Images/Key_3.png diff --git a/assets/Images/Key_4.png b/assets/Images/Key_4.png Binary files differnew file mode 100644 index 0000000..f09f283 --- /dev/null +++ b/assets/Images/Key_4.png diff --git a/assets/Images/flutter_demo.png b/assets/Images/flutter_demo.png Binary files differnew file mode 100644 index 0000000..fc9f425 --- /dev/null +++ b/assets/Images/flutter_demo.png diff --git a/assets/Images/grid.svg b/assets/Images/grid.svg new file mode 100644 index 0000000..f3554d1 --- /dev/null +++ b/assets/Images/grid.svg @@ -0,0 +1,13 @@ +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools --> +<svg fill="#ffffff" width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" stroke="#ffffff"> +
<g id="SVGRepo_bgCarrier" stroke-width="0"/> +
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/> +
<g id="SVGRepo_iconCarrier"> +
<title>ionicons-v5-i</title> +
<path d="M204,240H68a36,36,0,0,1-36-36V68A36,36,0,0,1,68,32H204a36,36,0,0,1,36,36V204A36,36,0,0,1,204,240Z"/> +
<path d="M444,240H308a36,36,0,0,1-36-36V68a36,36,0,0,1,36-36H444a36,36,0,0,1,36,36V204A36,36,0,0,1,444,240Z"/> +
<path d="M204,480H68a36,36,0,0,1-36-36V308a36,36,0,0,1,36-36H204a36,36,0,0,1,36,36V444A36,36,0,0,1,204,480Z"/> +
<path d="M444,480H308a36,36,0,0,1-36-36V308a36,36,0,0,1,36-36H444a36,36,0,0,1,36,36V444A36,36,0,0,1,444,480Z"/> +
</g> +
</svg>
\ No newline at end of file diff --git a/assets/Images/qt_demo.png b/assets/Images/qt_demo.png Binary files differnew file mode 100644 index 0000000..29bf526 --- /dev/null +++ b/assets/Images/qt_demo.png diff --git a/assets/res.qrc b/assets/res.qrc index d3f0c91..894da30 100644 --- a/assets/res.qrc +++ b/assets/res.qrc @@ -40,6 +40,13 @@ <file>carbon_icons/windy--strong-disabled.svg</file> </qresource> <qresource prefix="Images"> + <file>Images/grid.svg</file> + <file>Images/qt_demo.png</file> + <file>Images/flutter_demo.png</file> + <file>Images/Key_4.png</file> + <file>Images/Key_3.png</file> + <file>Images/Key_2.png</file> + <file>Images/Key_1.png</file> <file>Images/tire-pressure.svg</file> <file>Images/HMI_HVAC_Fan_Icon.svg</file> <file>Images/AGL_Icons_LaneDeparture_white.svg</file> diff --git a/extras/config.ini b/extras/config.ini index 409de83..d88dee9 100644 --- a/extras/config.ini +++ b/extras/config.ini @@ -7,6 +7,13 @@ file-playback-path = dbc-file-path = can-interface = +[keypad-feature] +enabled = false +keypad-only = false +ip = +port = +keys-to-hide = 3 + [vss-server] ip = localhost port = 55555 diff --git a/extras/config.py b/extras/config.py index 8df3497..4cff839 100644 --- a/extras/config.py +++ b/extras/config.py @@ -158,6 +158,25 @@ def save_config(new_config, auth_token, CA_File=None): config.write(configfile) +# check the keypad-features wanted + +def keypad_enabled(): + return config.getboolean('keypad-feature', 'enabled', fallback=False) + +def keypad_only(): + return config.getboolean('keypad-feature', 'keypad-only', fallback=False) + +def get_keypad_config(): + # return the ip and port of the keypad if specified, else return localhost and 8080 + ip = config.get('keypad-feature', 'ip', fallback=False) + port = config.get('keypad-feature', 'port', fallback=False) + return ip if ip else "localhost", port if port else "8080" + +def get_keypad_keys_to_hide(): + # return the keys to hide if specified, else return an empty + keys = config.get('keypad-feature', 'keys-to-hide', fallback=False) + return keys.split(',') if keys else [] + def fullscreen_mode(): return config.getboolean('default', 'fullscreen-mode', fallback=False) @@ -18,6 +18,7 @@ import sys import os from PyQt6 import uic, QtCore, QtWidgets +from PyQt6.QtWidgets import QFrame from PyQt6.QtWidgets import QApplication, QPushButton, QWidget from functools import partial from PyQt6 import QtGui @@ -54,6 +55,9 @@ class MainWindow(Base, Form): self.setStyle(QtWidgets.QStyleFactory.create('Fusion')) # set fullscreen mode if enabled in config.ini + if not config.keypad_enabled(): + self.keypadButton.hide() + if config.fullscreen_mode(): UI_Handeler.fullscreen(self) @@ -97,6 +101,7 @@ class MainWindow(Base, Form): self.icButton, self.hvacButton, self.steeringCtrlButton, + self.keypadButton, self.settingsBtn) steering_icon = ":/Images/Images/steering-wheel.svg" @@ -106,6 +111,10 @@ class MainWindow(Base, Form): self.hvacButton.hide() if not config.steering_wheel_enabled(): self.steeringCtrlButton.hide() + if not config.keypad_enabled(): + self.findChild(QFrame, 'keypadFrame').hide() + self.keypadButton.hide() + NavigationButtons = QtWidgets.QButtonGroup(self) NavigationButtons.setExclusive(True) @@ -121,9 +130,14 @@ class MainWindow(Base, Form): self.stackedWidget.currentChanged.connect(self.handleChangedPage) - self.stackedWidget.setCurrentIndex(0) - self.dashboardButton.setChecked(True) - UI_Handeler.Hide_Navbar(self, bool_arg=False) + if config.keypad_only(): + self.stackedWidget.setCurrentIndex(4) + self.keypadButton.setChecked(True) + UI_Handeler.Hide_Navbar(self, bool_arg=False) + else: + self.stackedWidget.setCurrentIndex(0) + self.dashboardButton.setChecked(True) + UI_Handeler.Hide_Navbar(self, bool_arg=False) self.Dashboard = Dashboard() self.Dashboard.tileClickedSignal.connect(self.handleTileClicked) @@ -165,12 +179,12 @@ class MainWindow(Base, Form): UI_Handeler.Hide_Navbar(self, hide_navbar) if self.current_page is not None: - if self.current_page != 0 and self.current_page != 4: + if self.current_page != 0 and self.current_page != 4 and self.current_page != 5: self.stackedWidget.widget(self.current_page).kuksa_client.stop() self.current_page = page_index - if self.current_page != 0 and self.current_page != 4: + if self.current_page != 0 and self.current_page != 4 and self.current_page != 5: self.stackedWidget.widget(self.current_page).kuksa_client.start() diff --git a/ui/Dashboard.ui b/ui/Dashboard.ui index f8c8938..e5d8cc0 100644 --- a/ui/Dashboard.ui +++ b/ui/Dashboard.ui @@ -55,7 +55,7 @@ QPushButton:pressed { <property name="bottomMargin"> <number>0</number> </property> - <item row="1" column="1"> + <item row="1" column="2"> <widget class="QPushButton" name="DB_Settings_Tile"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> @@ -92,8 +92,8 @@ QPushButton:pressed { </property> </widget> </item> - <item row="0" column="0"> - <widget class="QPushButton" name="DB_IC_Tile"> + <item row="1" column="0"> + <widget class="QPushButton" name="DB_Steering_Tile"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -112,11 +112,11 @@ QPushButton:pressed { <enum>Qt::LeftToRight</enum> </property> <property name="text"> - <string>Instrument Cluster</string> + <string>Steering Controls</string> </property> <property name="icon"> <iconset resource="../assets/res.qrc"> - <normaloff>:/Carbon_Icons/carbon_icons/meter.svg</normaloff>:/Carbon_Icons/carbon_icons/meter.svg</iconset> + <normaloff>:/Images/Images/steering-wheel.svg</normaloff>:/Images/Images/steering-wheel.svg</iconset> </property> <property name="iconSize"> <size> @@ -124,9 +124,12 @@ QPushButton:pressed { <height>45</height> </size> </property> + <property name="flat"> + <bool>false</bool> + </property> </widget> </item> - <item row="0" column="1"> + <item row="0" column="2"> <widget class="QPushButton" name="DB_HVAC_Tile"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> @@ -163,8 +166,72 @@ QPushButton:pressed { </property> </widget> </item> - <item row="1" column="0"> - <widget class="QPushButton" name="DB_Steering_Tile"> + <item row="1" column="1"> + <widget class="QFrame" name="keypadFrame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="DB_Keypad_Tile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>16</pointsize> + <weight>75</weight> + <italic>true</italic> + <bold>true</bold> + </font> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string>Keypad</string> + </property> + <property name="icon"> + <iconset resource="../assets/res.qrc"> + <normaloff>:/Images/Images/grid.svg</normaloff>:/Images/Images/grid.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>45</width> + <height>45</height> + </size> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QPushButton" name="DB_IC_Tile"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> @@ -183,11 +250,11 @@ QPushButton:pressed { <enum>Qt::LeftToRight</enum> </property> <property name="text"> - <string>Steering Controls</string> + <string>Instrument Cluster</string> </property> <property name="icon"> <iconset resource="../assets/res.qrc"> - <normaloff>:/Images/Images/steering-wheel.svg</normaloff>:/Images/Images/steering-wheel.svg</iconset> + <normaloff>:/Carbon_Icons/carbon_icons/meter.svg</normaloff>:/Carbon_Icons/carbon_icons/meter.svg</iconset> </property> <property name="iconSize"> <size> @@ -195,9 +262,6 @@ QPushButton:pressed { <height>45</height> </size> </property> - <property name="flat"> - <bool>false</bool> - </property> </widget> </item> </layout> @@ -170,12 +170,21 @@ QLCDNumber { <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <widget class="QDockWidget" name="TirePressureDock"> + <property name="minimumSize"> + <size> + <width>400</width> + <height>600</height> + </size> + </property> <property name="floating"> - <bool>false</bool> + <bool>true</bool> </property> <property name="features"> <set>QDockWidget::NoDockWidgetFeatures</set> </property> + <property name="allowedAreas"> + <set>Qt::LeftDockWidgetArea</set> + </property> <widget class="QWidget" name="dockWidgetContents"> <property name="autoFillBackground"> <bool>false</bool> @@ -236,69 +245,6 @@ QLCDNumber { <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="3" column="3" alignment="Qt::AlignBottom"> - <widget class="QSlider" name="Speed_slider"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>60</height> - </size> - </property> - <property name="font"> - <font> - <weight>50</weight> - <bold>false</bold> - </font> - </property> - <property name="maximum"> - <number>240</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::NoTicks</enum> - </property> - <property name="tickInterval"> - <number>0</number> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QWidget" name="Speed_Gauge_Placeholder" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="2" colspan="4"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>10</height> - </size> - </property> - </spacer> - </item> <item row="2" column="4"> <widget class="QWidget" name="RPM_Gauge_Placeholder" native="true"> <property name="sizePolicy"> @@ -309,25 +255,6 @@ QLCDNumber { </property> </widget> </item> - <item row="3" column="4" alignment="Qt::AlignBottom"> - <widget class="QSlider" name="RPM_slider"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>60</height> - </size> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> <item row="1" column="2" colspan="3"> <widget class="QFrame" name="frame_3"> <property name="sizePolicy"> @@ -355,6 +282,32 @@ QLCDNumber { <enum>QFrame::Raised</enum> </property> <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="4" rowspan="2"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1" rowspan="2"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> <item row="1" column="3"> <widget class="QPushButton" name="rightIndicatorBtn"> <property name="text"> @@ -418,35 +371,91 @@ QLCDNumber { </property> </widget> </item> - <item row="0" column="1" rowspan="2"> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="4" rowspan="2"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </item> + <item row="3" column="3" alignment="Qt::AlignBottom"> + <widget class="QSlider" name="Speed_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>60</height> + </size> + </property> + <property name="font"> + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="maximum"> + <number>240</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::NoTicks</enum> + </property> + <property name="tickInterval"> + <number>0</number> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QWidget" name="Speed_Gauge_Placeholder" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="4" alignment="Qt::AlignBottom"> + <widget class="QSlider" name="RPM_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>60</height> + </size> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="0" column="2" colspan="4"> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + </item> <item row="1" column="0" rowspan="4" colspan="2" alignment="Qt::AlignHCenter"> <widget class="QFrame" name="coolant_gauge_frame"> <property name="sizePolicy"> @@ -518,8 +527,8 @@ QLCDNumber { </property> <property name="minimumSize"> <size> - <width>0</width> - <height>0</height> + <width>200</width> + <height>200</height> </size> </property> </widget> @@ -594,8 +603,8 @@ QLCDNumber { </property> <property name="minimumSize"> <size> - <width>0</width> - <height>0</height> + <width>200</width> + <height>200</height> </size> </property> </widget> @@ -840,7 +849,7 @@ QLCDNumber { <item> <widget class="QPushButton" name="TirePressureBtn"> <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <sizepolicy hsizetype="Fixed" vsizetype="Minimum"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -848,7 +857,7 @@ QLCDNumber { <property name="minimumSize"> <size> <width>50</width> - <height>50</height> + <height>40</height> </size> </property> <property name="font"> @@ -869,8 +878,8 @@ QLCDNumber { </property> <property name="iconSize"> <size> - <width>50</width> - <height>50</height> + <width>40</width> + <height>40</height> </size> </property> <property name="checkable"> diff --git a/ui/Keypad.ui b/ui/Keypad.ui index cda5e42..056d8f8 100644 --- a/ui/Keypad.ui +++ b/ui/Keypad.ui @@ -1,13 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>HVAC</class> - <widget class="QWidget" name="HVAC"> + <class>Keypad</class> + <widget class="QWidget" name="Keypad"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>420</width> - <height>690</height> + <width>958</width> + <height>578</height> </rect> </property> <property name="windowTitle"> @@ -31,13 +31,13 @@ background-color: #131313 ; /* black */ } -#centralwidget QPushButton{ +#centralwidget QToolButton{ background-color: #6C6C85 ; /* pastel purple */ padding: 5px 10px; border-radius: 10px; } -#centralwidget QPushButton:pressed { +#centralwidget QToolButton:pressed { background-color: #4BD7D6 ; /* light blue */ } @@ -187,123 +187,181 @@ QListWidget::item:hover { <enum>QFrame::NoFrame</enum> </property> <layout class="QGridLayout" name="gridLayout_4"> - <item row="1" column="0"> - <widget class="QFrame" name="frame_2"> + <item row="0" column="0"> + <widget class="QFrame" name="frame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="1"> - <widget class="QPushButton" name="Key_2"> - <property name="text"> - <string/> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QFrame" name="frame_2"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> </property> - <property name="icon"> - <iconset> - <normaloff>:/Keypad_Images/keypad_icons/f2-unpressed.png</normaloff>:/Keypad_Images/keypad_icons/f2-unpressed.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>100</width> - <height>100</height> - </size> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QPushButton" name="Key_3"> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset> - <normaloff>:/Keypad_Images/keypad_icons/f3-unpressed.png</normaloff>:/Keypad_Images/keypad_icons/f3-unpressed.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>100</width> - <height>100</height> - </size> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QPushButton" name="Key_1"> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset> - <normaloff>:/Keypad_Images/keypad_icons/f1-unpressed.png</normaloff>:/Keypad_Images/keypad_icons/f1-unpressed.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>100</width> - <height>100</height> - </size> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QToolButton" name="Key_1"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../assets/res.qrc"> + <normaloff>:/Images/Images/flutter_demo.png</normaloff>:/Images/Images/flutter_demo.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>200</width> + <height>200</height> + </size> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextUnderIcon</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="Key_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../assets/res.qrc"> + <normaloff>:/Images/Images/qt_demo.png</normaloff>:/Images/Images/qt_demo.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>200</width> + <height>200</height> + </size> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextUnderIcon</enum> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="4" column="2"> - <widget class="QPushButton" name="Key_5"> - <property name="text"> - <string/> + <item> + <widget class="QFrame" name="frame_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <property name="icon"> - <iconset> - <normaloff>:/Keypad_Images/keypad_icons/f5-unpressed.png</normaloff>:/Keypad_Images/keypad_icons/f5-unpressed.png</iconset> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> </property> - <property name="iconSize"> - <size> - <width>100</width> - <height>100</height> - </size> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QToolButton" name="Key_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../assets/res.qrc"> + <normaloff>:/Images/Images/Key_3.png</normaloff>:/Images/Images/Key_3.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>200</width> + <height>200</height> + </size> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextUnderIcon</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="Key_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../assets/res.qrc"> + <normaloff>:/Images/Images/Key_4.png</normaloff>:/Images/Images/Key_4.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>200</width> + <height>200</height> + </size> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextUnderIcon</enum> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="4" column="0"> - <widget class="QPushButton" name="Key_4"> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset> - <normaloff>:/Keypad_Images/keypad_icons/f4-unpressed.png</normaloff>:/Keypad_Images/keypad_icons/f4-unpressed.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>100</width> - <height>100</height> - </size> - </property> - </widget> - </item> - <item row="4" column="1"> - <spacer name="horizontalSpacer"> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </item> - <item row="2" column="0"> - <spacer name="verticalSpacer"> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </item> |