aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Main_Window.ui26
-rw-r--r--QMLWidgets/Full_Gauge/RPMGauge.qml211
-rw-r--r--QMLWidgets/Full_Gauge/SpeedGauge.qml175
-rw-r--r--QMLWidgets/Half_Gauge/CoolantGauge.qml179
-rw-r--r--QMLWidgets/Half_Gauge/FuelGauge.qml181
-rw-r--r--QMLWidgets/Temp_Tumbler/TempTumbler.qml59
-rw-r--r--Scripts/record_playback.py94
-rw-r--r--Widgets/Dashboard.py11
-rw-r--r--Widgets/HVACPage.py13
-rw-r--r--Widgets/ICPage.py188
-rw-r--r--Widgets/Keypad.py56
-rw-r--r--assets/Images/Key_1.pngbin0 -> 10028 bytes
-rw-r--r--assets/Images/Key_2.pngbin0 -> 13214 bytes
-rw-r--r--assets/Images/Key_3.pngbin0 -> 13291 bytes
-rw-r--r--assets/Images/Key_4.pngbin0 -> 12071 bytes
-rw-r--r--assets/Images/flutter_demo.pngbin0 -> 2402 bytes
-rw-r--r--assets/Images/grid.svg13
-rw-r--r--assets/Images/qt_demo.pngbin0 -> 7410 bytes
-rw-r--r--assets/res.qrc7
-rw-r--r--extras/config.ini7
-rw-r--r--extras/config.py19
-rw-r--r--main.py24
-rw-r--r--ui/Dashboard.ui90
-rw-r--r--ui/IC.ui243
-rw-r--r--ui/Keypad.ui274
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
new file mode 100644
index 0000000..25cd0d0
--- /dev/null
+++ b/assets/Images/Key_1.png
Binary files differ
diff --git a/assets/Images/Key_2.png b/assets/Images/Key_2.png
new file mode 100644
index 0000000..e69e6bd
--- /dev/null
+++ b/assets/Images/Key_2.png
Binary files differ
diff --git a/assets/Images/Key_3.png b/assets/Images/Key_3.png
new file mode 100644
index 0000000..e72082d
--- /dev/null
+++ b/assets/Images/Key_3.png
Binary files differ
diff --git a/assets/Images/Key_4.png b/assets/Images/Key_4.png
new file mode 100644
index 0000000..f09f283
--- /dev/null
+++ b/assets/Images/Key_4.png
Binary files differ
diff --git a/assets/Images/flutter_demo.png b/assets/Images/flutter_demo.png
new file mode 100644
index 0000000..fc9f425
--- /dev/null
+++ b/assets/Images/flutter_demo.png
Binary files differ
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
new file mode 100644
index 0000000..29bf526
--- /dev/null
+++ b/assets/Images/qt_demo.png
Binary files differ
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)
diff --git a/main.py b/main.py
index 1fded6e..86d4f7f 100644
--- a/main.py
+++ b/main.py
@@ -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>
diff --git a/ui/IC.ui b/ui/IC.ui
index 961fc04..ad50997 100644
--- a/ui/IC.ui
+++ b/ui/IC.ui
@@ -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>