diff options
Diffstat (limited to 'Widgets')
-rw-r--r-- | Widgets/Dashboard.py | 76 | ||||
-rw-r--r-- | Widgets/HVACPage.py | 11 | ||||
-rw-r--r-- | Widgets/ICPage.py | 42 | ||||
-rw-r--r-- | Widgets/SteeringCtrlPage.py | 14 | ||||
-rw-r--r-- | Widgets/animatedToggle.py | 166 | ||||
-rw-r--r-- | Widgets/settings.py | 35 |
6 files changed, 249 insertions, 95 deletions
diff --git a/Widgets/Dashboard.py b/Widgets/Dashboard.py index 1992b14..9df290f 100644 --- a/Widgets/Dashboard.py +++ b/Widgets/Dashboard.py @@ -3,19 +3,17 @@ # # SPDX-License-Identifier: Apache-2.0 -from PyQt5 import QtCore, QtWidgets import os import sys -from PyQt5 import uic -from PyQt5 import QtWidgets -from PyQt5.QtWidgets import * -from PyQt5.QtSvg import * -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtGui import QIcon -from PyQt5 import QtCore -from PyQt5 import QtSvg - -from extras import config +from PyQt6 import uic +from PyQt6 import QtCore, QtWidgets +from PyQt6 import QtWidgets +from PyQt6.QtWidgets import * +from PyQt6.QtSvg import * +from PyQt6.QtCore import pyqtSignal +from PyQt6.QtGui import QIcon +from PyQt6.QtGui import QIcon +from PyQt6.QtCore import QSize current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -28,6 +26,8 @@ Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/Dashboard.ui")) # ======================================== +from extras import config +import res_rc class Dashboard(Base, Form): """ @@ -78,42 +78,34 @@ class Dashboard(Base, Form): DashboardTiles.addButton(tile) def set_icon(self, tile, icon_size): - icon_mapping = { - self.DB_IC_Tile: ":/Carbon_Icons/carbon_icons/meter.svg", - self.DB_HVAC_Tile: ":/Carbon_Icons/carbon_icons/windy--strong.svg", - self.DB_Steering_Tile: ":/Images/Images/steering-wheel.svg", - self.DB_Settings_Tile: ":/Carbon_Icons/carbon_icons/settings.svg" - } - icon_mapping_disabled = { - self.DB_IC_Tile: ":/Carbon_Icons/carbon_icons/meter-disabled.svg", - self.DB_HVAC_Tile: ":/Carbon_Icons/carbon_icons/windy--strong-disabled.svg", - self.DB_Steering_Tile: ":/Images/Images/steering-wheel-disabled.svg", - self.DB_Settings_Tile: ":/Carbon_Icons/carbon_icons/settings.svg" + icon_mappings = { + self.DB_IC_Tile: { + "normal": ":/Carbon_Icons/carbon_icons/meter.svg", + "disabled": ":/Carbon_Icons/carbon_icons/meter-disabled.svg" + }, + self.DB_HVAC_Tile: { + "normal": ":/Carbon_Icons/carbon_icons/windy--strong.svg", + "disabled": ":/Carbon_Icons/carbon_icons/windy--strong-disabled.svg" + }, + self.DB_Steering_Tile: { + "normal": ":/Images/Images/steering-wheel.svg", + "disabled": ":/Images/Images/steering-wheel-disabled.svg" + }, + self.DB_Settings_Tile: { + "normal": ":/Carbon_Icons/carbon_icons/settings.svg", + "disabled": ":/Carbon_Icons/carbon_icons/settings.svg" # Assuming the same icon for simplicity + } } + icon_key = "disabled" if not tile.isEnabled() else "normal" + file_path = icon_mappings.get(tile, {}).get(icon_key) - file = icon_mapping.get(tile) - if file is None: + if not file_path: return - getsize = QtSvg.QSvgRenderer(file) - svg_widget = QtSvg.QSvgWidget(file) - svg_widget.setFixedSize(getsize.defaultSize()*2) - svg_widget.setStyleSheet("background-color: transparent;") - icon = QIcon(svg_widget.grab()) - - file = icon_mapping_disabled.get(tile) - if file is None: - return - - getsize = QtSvg.QSvgRenderer(file) - svg_widget = QtSvg.QSvgWidget(file) - svg_widget.setFixedSize(getsize.defaultSize()*2) - svg_widget.setStyleSheet("background-color: transparent;") - icon.addPixmap(svg_widget.grab(), QIcon.Disabled, QIcon.Off) - + icon = QIcon(file_path) tile.setIcon(icon) - tile.setIconSize(QtCore.QSize(icon_size, icon_size)) + tile.setIconSize(QSize(icon_size, icon_size)) def tile_clicked(self, tile): """ @@ -139,4 +131,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = Dashboard() w.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/Widgets/HVACPage.py b/Widgets/HVACPage.py index 0c25c58..d101e15 100644 --- a/Widgets/HVACPage.py +++ b/Widgets/HVACPage.py @@ -3,11 +3,10 @@ # # SPDX-License-Identifier: Apache-2.0 -from extras.KuksaClient import KuksaClient import os import sys -from PyQt5 import uic -from PyQt5.QtWidgets import QApplication, QListWidget, QSlider, QPushButton +from PyQt6 import uic +from PyQt6.QtWidgets import QApplication, QListWidget, QSlider, QPushButton current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -20,6 +19,8 @@ Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/HVAC.ui")) # ======================================== +from extras.KuksaClient import KuksaClient +import res_rc class HVAC_Paths(): def __init__(self): @@ -115,7 +116,7 @@ class HVACWidget(Base, Form): def setTemperature(self, list_widget, path): item = list_widget.currentItem() if item is not None: - list_widget.scrollToItem(item, 1) + list_widget.scrollToItem(item) self.kuksa_client.set(path, item.text()[:-2], "targetValue") print(item.text()) @@ -145,4 +146,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = HVACWidget() w.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/Widgets/ICPage.py b/Widgets/ICPage.py index 4a32211..f2e41a7 100644 --- a/Widgets/ICPage.py +++ b/Widgets/ICPage.py @@ -6,14 +6,11 @@ import os import logging import sys -from PyQt5 import uic, QtCore, QtWidgets -from PyQt5.QtWidgets import QApplication -from PyQt5.QtGui import QIcon, QPixmap, QPainter -from PyQt5.QtCore import QObject, pyqtSignal -from PyQt5.QtWidgets import QWidget -from qtwidgets import AnimatedToggle -from extras.KuksaClient import KuksaClient -from extras.VehicleSimulator import VehicleSimulator +from PyQt6 import uic, QtCore, QtWidgets +from PyQt6.QtWidgets import QApplication +from PyQt6.QtGui import QIcon, QPixmap, QPainter +from PyQt6.QtCore import QObject, pyqtSignal +from PyQt6.QtWidgets import QWidget current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -26,6 +23,10 @@ Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/IC.ui")) # ======================================== +from extras.KuksaClient import KuksaClient +from extras.VehicleSimulator import VehicleSimulator +import res_rc +from Widgets.animatedToggle import AnimatedToggle class IC_Paths(): def __init__(self): @@ -66,10 +67,7 @@ class ICWidget(Base, Form): self.IC_Frame = self.findChild(QWidget, "frame_1") - self.Script_toggle = AnimatedToggle( - checked_color="#4BD7D6", - pulse_checked_color="#00ffff" - ) + self.Script_toggle = AnimatedToggle() layout.replaceWidget(self.demoToggle, self.Script_toggle) self.demoToggle.deleteLater() @@ -175,13 +173,13 @@ class ICWidget(Base, Form): """ hazardIcon = QPixmap(":/Images/Images/hazard.png") painter = QPainter(hazardIcon) - painter.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) if self.hazardBtn.isChecked(): - color = QtCore.Qt.yellow + color = QtCore.Qt.GlobalColor.yellow value = "true" else: - color = QtCore.Qt.black + color = QtCore.Qt.GlobalColor.black value = "false" painter.fillRect(hazardIcon.rect(), color) @@ -204,13 +202,13 @@ class ICWidget(Base, Form): """ leftIndicatorIcon = QPixmap(":/Images/Images/left.png") painter = QPainter(leftIndicatorIcon) - painter.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) if self.leftIndicatorBtn.isChecked(): - color = QtCore.Qt.green + color = QtCore.Qt.GlobalColor.green value = "true" else: - color = QtCore.Qt.black + color = QtCore.Qt.GlobalColor.black value = "false" painter.fillRect(leftIndicatorIcon.rect(), color) @@ -228,13 +226,13 @@ class ICWidget(Base, Form): """ rightIndicatorIcon = QPixmap(":/Images/Images/right.png") painter = QPainter(rightIndicatorIcon) - painter.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) if self.rightIndicatorBtn.isChecked(): - color = QtCore.Qt.green + color = QtCore.Qt.GlobalColor.green value = "true" else: - color = QtCore.Qt.black + color = QtCore.Qt.GlobalColor.black value = "false" painter.fillRect(rightIndicatorIcon.rect(), color) @@ -371,4 +369,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = ICWidget() w.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/Widgets/SteeringCtrlPage.py b/Widgets/SteeringCtrlPage.py index 7e0a131..5eb486d 100644 --- a/Widgets/SteeringCtrlPage.py +++ b/Widgets/SteeringCtrlPage.py @@ -3,13 +3,10 @@ # # SPDX-License-Identifier: Apache-2.0 -from . import settings -import extras.FeedCAN as feed_can -from extras.KuksaClient import KuksaClient import os import sys -from PyQt5 import uic -from PyQt5.QtWidgets import QApplication, QButtonGroup +from PyQt6 import uic +from PyQt6.QtWidgets import QApplication, QButtonGroup current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -24,6 +21,11 @@ Form, Base = uic.loadUiType(os.path.join( # ======================================== +import extras.FeedCAN as feed_can +from Widgets import settings +from extras.KuksaClient import KuksaClient +import res_rc + class Steering_Paths(): def __init__(self): self.switches = { @@ -142,4 +144,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = SteeringCtrlWidget() w.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/Widgets/animatedToggle.py b/Widgets/animatedToggle.py new file mode 100644 index 0000000..7cfe254 --- /dev/null +++ b/Widgets/animatedToggle.py @@ -0,0 +1,166 @@ +# Copyright (C) 2024 Suchinton Chakravarty +# +# SPDX-License-Identifier: Apache-2.0 + +import sys +from PyQt6.QtGui import QColor, QPainter, QPainterPath, QBrush +from PyQt6.QtCore import pyqtProperty, QPropertyAnimation, QPoint, QEasingCurve +from PyQt6.QtWidgets import QApplication, QCheckBox + + +class AnimatedToggle(QCheckBox): + """ + A custom toggle switch widget with animation effects. + + Inherits QCheckBox class from PyQt6.QtWidgets module. + """ + + bg_color = pyqtProperty( + QColor, lambda self: self._bg_color, + lambda self, col: setattr(self, '_bg_color', col)) + circle_color = pyqtProperty( + QColor, lambda self: self._circle_color, + lambda self, col: setattr(self, '_circle_color', col)) + active_color = pyqtProperty( + QColor, lambda self: self._active_color, + lambda self, col: setattr(self, '_active_color', col)) + disabled_color = pyqtProperty( + QColor, lambda self: self._disabled_color, + lambda self, col: setattr(self, '_disabled_color', col)) + circle_pos = pyqtProperty( + float, lambda self: self._circle_pos, + lambda self, pos: (setattr(self, '_circle_pos', pos), self.update())) + intermediate_bg_color = pyqtProperty( + QColor, lambda self: self._intermediate_bg_color, + lambda self, col: setattr(self, '_intermediate_bg_color', col)) + + def __init__(self, parent=None): + """ + Constructs an AnimatedToggle object. + + Parameters + ---------- + parent : QWidget, optional + The parent widget of the toggle switch (default is None). + + """ + super().__init__(parent) + self._bg_color = QColor("#965D62") + self._circle_color = QColor("#DDD") + self._active_color = QColor('#4BD7D6') + self._disabled_color = QColor('#965D62') + self._circle_pos = None + self._intermediate_bg_color = None + self._animation_duration = 500 # milliseconds + self._user_checked = False + + self.setFixedHeight(28) + self.stateChanged.connect(self.start_transition) + + def setDuration(self, duration: int): + """ + Sets the duration of the animation. + + Parameters + ---------- + duration : int + The duration of the animation in milliseconds. + + """ + self._animation_duration = duration + + def update_pos_color(self, checked=None): + self._circle_pos = self.height() * (1.1 if checked else 0.1) + if self.isChecked(): + self._intermediate_bg_color = self._active_color + else: + self._intermediate_bg_color = self._bg_color + + def start_transition(self, state): + if not self._user_checked: + self.update_pos_color(state) + return + for anim in [self.create_animation, self.create_bg_color_animation]: + animation = anim(state) + animation.start() + self._user_checked = False + + def mousePressEvent(self, event): + self._user_checked = True + super().mousePressEvent(event) + + def create_animation(self, state): + return self._create_common_animation(state, b'circle_pos', self.height() * 0.1, self.height() * 1.1) + + def create_bg_color_animation(self, state): + return self._create_common_animation(state, b'intermediate_bg_color', self._bg_color, self._active_color) + + def _create_common_animation(self, state, prop, start_val, end_val): + animation = QPropertyAnimation(self, prop, self) + animation.setEasingCurve(QEasingCurve.Type.OutBounce) + animation.setDuration(self._animation_duration) + animation.setStartValue(start_val if state else end_val) + animation.setEndValue(end_val if state else start_val) + return animation + + def showEvent(self, event): + super().showEvent(event) + self.update_pos_color(self.isChecked()) + + def resizeEvent(self, event): + self.update_pos_color(self.isChecked()) + + def sizeHint(self): + size = super().sizeHint() + size.setWidth(self.height() * 2) + return size + + def hitButton(self, pos: QPoint): + return self.contentsRect().contains(pos) + + def paintEvent(self, event): + """ + Handles the paint event of the toggle switch. + + Parameters + ---------- + event : QPaintEvent + The paint event. + + """ + painter = QPainter(self) + painter.setRenderHint(QPainter.RenderHint.Antialiasing) + + circle_color = QColor( + self.disabled_color if not self.isEnabled() else self.circle_color) + bg_color = QColor(self.disabled_color if not self.isEnabled() else self.intermediate_bg_color) \ + if self.intermediate_bg_color is not None else QColor("transparent") + + border_radius = self.height() / 2 + toggle_width = self.height() * 2 + toggle_margin = self.height() * 0.3 + circle_size = self.height() * 0.8 + + if self.circle_pos is None: + self.update_pos_color(self.isChecked()) + + bg_path = QPainterPath() + bg_path.addRoundedRect( + 0, 0, toggle_width, self.height(), border_radius, border_radius) + painter.fillPath(bg_path, QBrush(bg_color)) + + circle = QPainterPath() + circle.addEllipse(self.circle_pos, self.height() + * 0.1, circle_size, circle_size) + painter.fillPath(circle, QBrush(circle_color)) + + self.setStyleSheet(f"background-color: {bg_color.name()};") + + painter.end() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = AnimatedToggle() + window.show() + sys.exit(app.exec()) diff --git a/Widgets/settings.py b/Widgets/settings.py index 08f6a00..4adf72d 100644 --- a/Widgets/settings.py +++ b/Widgets/settings.py @@ -3,18 +3,16 @@ # # SPDX-License-Identifier: Apache-2.0 -from extras import config -import extras.Kuksa_Instance as kuksa_instance + import os import sys import time -from PyQt5 import uic -from PyQt5.QtWidgets import QApplication, QLineEdit, QPushButton, QLabel, QComboBox, QStyledItemDelegate -from qtwidgets import AnimatedToggle -from PyQt5.QtWidgets import QWidget -from PyQt5.QtCore import QThread -from PyQt5 import QtGui +from PyQt6.QtWidgets import QApplication, QLineEdit, QPushButton, QLabel +from PyQt6 import uic +from PyQt6.QtWidgets import QWidget +from PyQt6.QtCore import QThread +from PyQt6 import QtGui import logging import can @@ -24,6 +22,11 @@ current_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.dirname(current_dir)) +from extras import config +import extras.Kuksa_Instance as kuksa_instance +from Widgets.animatedToggle import AnimatedToggle +import res_rc + Form, Base = uic.loadUiType(os.path.join( current_dir, "../ui/Settings_Window.ui")) @@ -34,14 +37,6 @@ Form, Base = uic.loadUiType(os.path.join( Steering_Signal_Type = "Kuksa" Protocol = None -def create_animated_toggle(): - return AnimatedToggle( - checked_color="#4BD7D6", - pulse_checked_color="#00ffff", - pulse_unchecked_color= "#4BD7D6", - ) - - class settings(Base, Form): """ A class representing the settings widget of the AGL Demo Control Panel. @@ -64,8 +59,8 @@ class settings(Base, Form): self.setupUi(self) self.client = None - self.SSL_toggle = create_animated_toggle() - self.Protocol_toggle = create_animated_toggle() + self.SSL_toggle = AnimatedToggle() + self.Protocol_toggle = AnimatedToggle() self.connectionStatus = self.findChild(QLabel, "connectionStatus") self.connectionLogo = self.findChild(QLabel, "connectionLogo") @@ -96,7 +91,7 @@ class settings(Base, Form): GS_layout.replaceWidget(self.place_holder_toggle_1, self.SSL_toggle) GS_layout.replaceWidget( - self.place_holder_toggle_2, self.Protocol_toggle) + self.place_holder_toggle_2, self.Protocol_toggle) self.place_holder_toggle_1.deleteLater() self.place_holder_toggle_2.deleteLater() @@ -294,4 +289,4 @@ if __name__ == '__main__': app = QApplication(sys.argv) w = settings() w.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) |