aboutsummaryrefslogtreecommitdiffstats
path: root/Widgets
diff options
context:
space:
mode:
authorSuchinton Chakravarty <suchinton.2001@gmail.com>2024-10-15 23:57:36 +0530
committerSuchinton Chakravarty <suchinton.2001@gmail.com>2024-10-22 16:09:43 +0530
commit6fdddee7d45206dc64eacd08700f79566ad9b4a6 (patch)
tree7d688595f69cdb7d7484f37542059d7406da28c5 /Widgets
parent2e2dd79e41b27a1d50be3c118955cdbd76e65539 (diff)
Fix Visual Bugs and Add options for Keypad input
- Fixed spin wheel input alignment for HVAC controls - Minor tweaks to Gauge input, Added new tick marks and improved gradient - Adding option(s) in config to handle Keypad input settings - Reconnect QML signals to enable two way input for Speed, RPM and other QML elements - Refactor and Add CLI option to start and stop playback. - Make Tire Pressure Dock into floating window and align to screen center. - Update resources to include keypad icons. - Add new tile for Keypad inputs Bug-AGL: SPEC-5161 Change-Id: I1ecefdfd114ecad081c138e74c1598907d91fd23 Signed-off-by: Suchinton Chakravarty <suchinton.2001@gmail.com>
Diffstat (limited to 'Widgets')
-rw-r--r--Widgets/Dashboard.py11
-rw-r--r--Widgets/HVACPage.py13
-rw-r--r--Widgets/ICPage.py188
-rw-r--r--Widgets/Keypad.py56
4 files changed, 199 insertions, 69 deletions
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