From 20fe2d131df0041e121eccaf4fc58d4ac88dfbbc Mon Sep 17 00:00:00 2001 From: suchinton2001 Date: Sun, 15 Oct 2023 23:30:36 +0530 Subject: agl-demo-control-panel: Refactor Settings, Config and UI scaling V1: - Add template to specify new configs in config.ini - Add drop-down to load all configurations specified in config.ini - Add new assets and refine UI elements (Scaling issue fixed) - Add size grip to main window - Add options in settings to configure port and AGL's CA.pem file - Removed unused or redundant files V2: - Check for user configs agl-demo-control-panel.ini & config.ini before resorting to default config.ini - Check for CA.pem and jwt tokens in default paths - Add new fields in settings for CA.pem file, jwt token path, TLS Server name - Fix crash in dashboard.py module due to icon.availableSizes() V3: Add Start/Stop states for the client V4: Block subscription event updates to the UI when values are changed on the control panel Bug-AGL: SPEC-4905 Signed-off-by: suchinton2001 Change-Id: Id7883ba3bc88248dabb58d54e6e931f6d365fd54 --- Main_Window.ui | 726 ++++++++++------------ Scripts/reset_tap.sh | 22 - Scripts/revert_tap_wireless_int.sh | 53 -- Scripts/setup_tap.sh | 84 --- Widgets/Dashboard.py | 13 +- Widgets/HVACPage.py | 33 + Widgets/SteeringCtrlPage.py | 9 +- Widgets/settings.py | 165 +++-- assets/carbon_icons/chevron--down.svg | 10 + assets/carbon_icons/chevron--up.svg | 10 + assets/carbon_icons/corner.svg | 9 + assets/carbon_icons/stop.svg | 1 + assets/res.qrc | 4 + extras/FeedKuksa.py | 42 +- extras/Kuksa_Instance.py | 35 +- extras/UI_Handeler.py | 19 +- extras/config.ini | 48 ++ extras/config.py | 99 ++- main.py | 22 +- ui/HVAC.ui | 1005 +++++++++++++++++------------- ui/IC.ui | 1094 +++++++++++++++++---------------- ui/Settings_Window.ui | 669 +++++++++++--------- ui/SteeringControls.ui | 540 ++++++++-------- 23 files changed, 2554 insertions(+), 2158 deletions(-) delete mode 100644 Scripts/reset_tap.sh delete mode 100644 Scripts/revert_tap_wireless_int.sh delete mode 100644 Scripts/setup_tap.sh create mode 100644 assets/carbon_icons/chevron--down.svg create mode 100644 assets/carbon_icons/chevron--up.svg create mode 100644 assets/carbon_icons/corner.svg create mode 100644 assets/carbon_icons/stop.svg create mode 100644 extras/config.ini diff --git a/Main_Window.ui b/Main_Window.ui index 6b8ba83..7bfb0ef 100644 --- a/Main_Window.ui +++ b/Main_Window.ui @@ -9,8 +9,8 @@ 0 0 - 1297 - 739 + 903 + 705 @@ -542,19 +542,16 @@ QStackedWidget{ false - - - + + + - + 0 0 - - - - + 0 @@ -571,37 +568,89 @@ QStackedWidget{ 0 - + - + 0 0 - - - 0 - 70 - + + true - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - 0 - 0 - - + QFrame::StyledPanel QFrame::Raised - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 60 + 60 + + + + + 90 + 55 + + + + + + + :/Images/Images/logo_agl.png + + + true + + + - + DejaVu Sans @@ -611,192 +660,143 @@ QStackedWidget{ - - - - - :/Carbon_Icons/carbon_icons/workspace.svg:/Carbon_Icons/carbon_icons/workspace.svg - - - - 35 - 35 - + AGL Demo Control Panel - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 40 - 20 - - - - - - - - - 0 - 0 - - + + QFrame::StyledPanel QFrame::Raised - + + + 6 + + + 0 + + + 0 + + + 6 + + + 0 + - - - true - - - - 0 - 0 - - - - - DejaVu Sans - 75 - true - true - true - - + - :/Carbon_Icons/carbon_icons/meter.svg:/Carbon_Icons/carbon_icons/meter.svg + :/Carbon_Icons/carbon_icons/subtract.svg:/Carbon_Icons/carbon_icons/subtract.svg - - - 35 - 35 - + + false - - - - DejaVu Sans - 75 - true - true - true - - + - :/Carbon_Icons/carbon_icons/windy--strong.svg:/Carbon_Icons/carbon_icons/windy--strong.svg - - - - 35 - 35 - + :/Carbon_Icons/carbon_icons/scale.svg:/Carbon_Icons/carbon_icons/scale.svg - - - - DejaVu Sans - 75 - true - true - true - - + - :/Images/Images/steering-wheel.svg:/Images/Images/steering-wheel.svg - - - - 35 - 35 - + :/Carbon_Icons/carbon_icons/close.svg:/Carbon_Icons/carbon_icons/close.svg + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - Qt::Horizontal - - - QSizePolicy::Maximum + + + + 0 + 0 + - - - 40 - 20 - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - DejaVu Sans - 75 - true - true - - - - Configure - - - - :/Carbon_Icons/carbon_icons/settings.svg:/Carbon_Icons/carbon_icons/settings.svg + + + + 0 + 0 + - - - 35 - 35 - + + 3 + + + + + @@ -808,15 +808,18 @@ QStackedWidget{ - - + + - + 0 0 - + + + + 0 @@ -832,90 +835,44 @@ QStackedWidget{ 0 - - + + - + 0 0 - - true + + + 0 + 70 + - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - + + + + + + 0 + 0 + + QFrame::StyledPanel QFrame::Raised - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - + + + - + 0 0 - - - 60 - 60 - - - - - 90 - 55 - - - - - - - :/Images/Images/logo_agl.png - - - true - - - - - DejaVu Sans @@ -925,22 +882,54 @@ QStackedWidget{ - AGL Demo Control Panel + + + + + :/Carbon_Icons/carbon_icons/workspace.svg:/Carbon_Icons/carbon_icons/workspace.svg + + + + 35 + 35 + - - + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + + 0 + 0 + + QFrame::StyledPanel QFrame::Raised - + 6 @@ -951,213 +940,168 @@ QStackedWidget{ 0 - 6 + 0 0 - - - Qt::Vertical + + + true + + + + 0 + 0 + + + + + DejaVu Sans + 75 + true + true + true + - - - - - :/Carbon_Icons/carbon_icons/subtract.svg:/Carbon_Icons/carbon_icons/subtract.svg + :/Carbon_Icons/carbon_icons/meter.svg:/Carbon_Icons/carbon_icons/meter.svg - - false + + + 35 + 35 + - + + + + 0 + 0 + + + + + DejaVu Sans + 75 + true + true + true + + - :/Carbon_Icons/carbon_icons/scale.svg:/Carbon_Icons/carbon_icons/scale.svg + :/Carbon_Icons/carbon_icons/windy--strong.svg:/Carbon_Icons/carbon_icons/windy--strong.svg + + + + 35 + 35 + - + + + + 0 + 0 + + + + + DejaVu Sans + 75 + true + true + true + + - :/Carbon_Icons/carbon_icons/close.svg:/Carbon_Icons/carbon_icons/close.svg + :/Images/Images/steering-wheel.svg:/Images/Images/steering-wheel.svg - - - - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 1 + + + 35 + 35 + - - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 100 - - - - + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + QFrame::StyledPanel QFrame::Raised - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - :/icons/feather/alert-octagon.svg - - - - - - - - 0 - 0 - - - - Establish Connection to server - - - - - - - - + + + - + 0 0 - - - 40 - 0 - + + + DejaVu Sans + 75 + true + true + - OK - - - - - - - Qt::Horizontal + Configure - - QSizePolicy::Fixed + + + :/Carbon_Icons/carbon_icons/settings.svg:/Carbon_Icons/carbon_icons/settings.svg - + - 20 - 20 + 35 + 35 - + diff --git a/Scripts/reset_tap.sh b/Scripts/reset_tap.sh deleted file mode 100644 index d8080cd..0000000 --- a/Scripts/reset_tap.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [[ $EUID > 0 ]]; then - echo "Run this script as root" - exit -fi - -BRIDGE="br0" -TAP="tap0" - -echo "Removing bridge $BRIDGE" -ip link delete $BRIDGE type bridge - -echo "Removing tap $TAP" -ip link delete $TAP type tap - -echo "Setting $INTERFACE up" -ip link set up dev $INTERFACE - -echo "Starting NetworkManager" -systemctl start NetworkManager - diff --git a/Scripts/revert_tap_wireless_int.sh b/Scripts/revert_tap_wireless_int.sh deleted file mode 100644 index b23cf3a..0000000 --- a/Scripts/revert_tap_wireless_int.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -BRIDGE=br0 -NETWORK=10.10.10.0 -NETMASK=255.255.255.0 -GATEWAY=10.10.10.1 -DHCPRANGE=10.10.10.100,10.10.10.254 - -# Delete the bridge interface -ip link delete dev $BRIDGE type bridge - -# Disable IP forwarding -sysctl -w net.ipv4.ip_forward=0 > /dev/null 2>&1 - -# Flush existing iptables rules and set default policies to ACCEPT -iptables --flush -iptables -t nat -F -iptables -X -iptables -Z -iptables -P OUTPUT ACCEPT -iptables -P INPUT ACCEPT -iptables -P FORWARD ACCEPT - -# Allow DHCP and DNS traffic on the network interface -iptables -A INPUT -i $BRIDGE -p tcp -m tcp --dport 67 -j ACCEPT -iptables -A INPUT -i $BRIDGE -p udp -m udp --dport 67 -j ACCEPT -iptables -A INPUT -i $BRIDGE -p tcp -m tcp --dport 53 -j ACCEPT -iptables -A INPUT -i $BRIDGE -p udp -m udp --dport 53 -j ACCEPT - -# Allow forwarding of packets between the network and the bridge -iptables -A FORWARD -s $NETWORK/$NETMASK -i $BRIDGE -j ACCEPT -iptables -A FORWARD -d $NETWORK/$NETMASK -o $BRIDGE -m state --state RELATED,ESTABLISHED -j ACCEPT - -# Delete the network address translation (NAT) rules -iptables -t nat -D POSTROUTING -s $NETWORK/$NETMASK -d $NETWORK/$NETMASK -j ACCEPT -iptables -t nat -D POSTROUTING -s $NETWORK/$NETMASK -j MASQUERADE - -# Delete the dnsmasq process -pid_file="/var/run/qemu-dnsmasq-$BRIDGE.pid" -if [ -f "$pid_file" ]; then - kill $(cat "$pid_file") - rm "$pid_file" -fi - -# Remove the wireless interface from the forwarding rules -iptables -D FORWARD -i $BRIDGE -o $WIRELESS -j ACCEPT -iptables -t nat -D POSTROUTING -o $WIRELESS -j MASQUERADE - -# Allow known traffic from the wireless interface to return to the network interface -iptables -D FORWARD -i $WIRELESS -o $BRIDGE -m state --state RELATED,ESTABLISHED -j ACCEPT - -echo "Reverted back to default configuration." - diff --git a/Scripts/setup_tap.sh b/Scripts/setup_tap.sh deleted file mode 100644 index 1c71344..0000000 --- a/Scripts/setup_tap.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -if [[ $EUID > 0 ]]; then - echo "Run this script as root" - exit -fi - -BRIDGE="br0" -TAP="tap0" - -echo "Available network interfaces:" -interfaces=$(ip link | awk -F ': ' '{print $2}') -index=0 - -# Array to store interface names -declare -a interface_names - -# Array to store interface types -declare -a interface_types - -# Loop through each interface and display its type -for interface in $interfaces; do - type=$(ip link show $interface | grep -o 'type .*' | awk '{print $2}') - echo "$index: $interface - $type" - - # Store interface name and type in arrays - interface_names[$index]=$interface - interface_types[$index]=$type - - ((index++)) -done - -# Prompt the user to select an interface -read -p "Enter the number of the interface you want to use: " selection - -# Validate the user's input -if [[ ! $selection =~ ^[0-9]+$ || $selection -lt 0 || $selection -ge $index ]]; then - echo "Invalid selection. Exiting." - exit -fi - -INTERFACE=${interface_names[$selection]} -INTERFACE_TYPE=${interface_types[$selection]} - -echo "Selected interface: $INTERFACE - $INTERFACE_TYPE" - -echo "Adding bridge $BRIDGE" -ip link add name $BRIDGE type bridge - -echo "Flushing interface $INTERFACE" -ip addr flush dev $INTERFACE - -echo "Setting $BRIDGE as master of $INTERFACE" -ip link set $INTERFACE master $BRIDGE - -echo "Adding tap $TAP" -ip tuntap add $TAP mode tap - -echo "Setting $BRIDGE as master of $TAP" -ip link set $TAP master $BRIDGE - -echo "Setting $INTERFACE, $BRIDGE, and $TAP up" -ip link set up dev $INTERFACE -ip link set up dev $TAP -ip link set up dev $BRIDGE - -echo "Stopping NetworkManager" -systemctl stop NetworkManager - -echo "Requesting IP for $BRIDGE" -dhclient -1 -v $BRIDGE - -if [ $? -eq 0 ]; then - echo "Requesting IP for $INTERFACE" - dhclient $INTERFACE - echo "Killing dhclient and starting NetworkManager" - pkill -9 dhclient - systemctl start NetworkManager -fi - -# run qemu with the below arguments -# -# qemu-system-x86_64 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -device virtio-net-pci,netdev=net0 - diff --git a/Widgets/Dashboard.py b/Widgets/Dashboard.py index 1d77e53..e7e17a6 100644 --- a/Widgets/Dashboard.py +++ b/Widgets/Dashboard.py @@ -84,10 +84,15 @@ class Dashboard(Base, Form): - tile: The tile for which the icon needs to be set. - size: The size of the icon. """ - icon = tile.icon() - scaled_pixmap = icon.pixmap(icon.availableSizes()[0]).scaled(size, size, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) - tile.setIcon(QtGui.QIcon(scaled_pixmap)) - tile.setIconSize(QtCore.QSize(size, size)) + try: + icon = tile.icon() + if icon.availableSizes(): + pixmap = icon.pixmap(icon.availableSizes()[0]) + scaled_pixmap = pixmap.scaled(size, size, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) + tile.setIcon(QtGui.QIcon(scaled_pixmap)) + tile.setIconSize(QtCore.QSize(size, size)) + except Exception as e: + print(f"Failed to set icon: {e}") def tile_clicked(self, tile): """ diff --git a/Widgets/HVACPage.py b/Widgets/HVACPage.py index 99ee798..312f82b 100644 --- a/Widgets/HVACPage.py +++ b/Widgets/HVACPage.py @@ -42,7 +42,20 @@ class HVAC_Paths(): self.temperatureList = [str(i) + "°C" for i in range(32, 15, -1)] class HVACWidget(Base, Form): + """ + A widget for controlling HVAC settings. + + Inherits from Base and Form. + """ + def __init__(self, parent=None): + """ + Initializes the HVACWidget. + + Args: + - parent: The parent widget. Defaults to None. + """ + super(self.__class__, self).__init__(parent) self.setupUi(self) @@ -83,23 +96,43 @@ class HVACWidget(Base, Form): self.rightFanSpeed_slider.valueChanged.connect(self.rightFanSpeed_sliderChanged) def leftTempListClicked(self): + """ + Handles the event when an item in the left temperature list is clicked. + Sends the selected temperature value to the feed_kuksa object. + """ + item = self.leftTempList.currentItem() self.leftTempList.scrollToItem(item, 1) self.feed_kuksa.send_values(self.HVAC.leftTemp, item.text()[:-2]) print(item.text()) def rightTempListClicked(self): + """ + Handles the event when an item in the right temperature list is clicked. + Sends the selected temperature value to the feed_kuksa object. + """ + item = self.rightTempList.currentItem() self.rightTempList.scrollToItem(item, 1) self.feed_kuksa.send_values(self.HVAC.rightTemp, item.text()[:-2]) print(item.text()) def leftFanSpeed_sliderChanged(self): + """ + Handles the event when the left fan speed slider is changed. + Sends the selected fan speed value to the feed_kuksa object. + """ + value = self.leftFanSpeed_slider.value() self.feed_kuksa.send_values(self.HVAC.leftFanSpeed, str(value)) print(value) def rightFanSpeed_sliderChanged(self): + """ + Handles the event when the right fan speed slider is changed. + Sends the selected fan speed value to the feed_kuksa object. + """ + value = self.rightFanSpeed_slider.value() self.feed_kuksa.send_values(self.HVAC.rightFanSpeed, str(value)) print(value) diff --git a/Widgets/SteeringCtrlPage.py b/Widgets/SteeringCtrlPage.py index 696c6c9..de3585d 100644 --- a/Widgets/SteeringCtrlPage.py +++ b/Widgets/SteeringCtrlPage.py @@ -18,9 +18,6 @@ import os import sys from PyQt5 import uic from PyQt5.QtWidgets import QApplication, QButtonGroup -from PyQt5.QtCore import QThread - -import time current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -120,6 +117,7 @@ class SteeringCtrlWidget(Base, Form): self.PhoneHangup, self.Voice, self.LaneDeparture, + self.Horn, self.CruiseEnable, self.CruiseSet, self.CruiseResume, @@ -138,13 +136,12 @@ class SteeringCtrlWidget(Base, Form): button_clicked = button.objectName() signal_type = settings.Steering_Signal_Type if signal_type == "Kuksa": - self.feed_kuksa.send_values(self.Steering.switches[button_clicked]["Kuksa"], 1) - self.feed_kuksa.send_values(self.Steering.switches[button_clicked]["Kuksa"], 0) + self.feed_kuksa.send_values(self.Steering.switches[button_clicked]["Kuksa"], "1") + self.feed_kuksa.send_values(self.Steering.switches[button_clicked]["Kuksa"], "0") elif signal_type == "CAN": feed_can.send_can_signal(self.Steering.switches[button_clicked]["CAN"]) # Making sure button state goes back to off feed_can.send_can_signal("021#FFFFFFFF00000000") - print(button_clicked + " button clicked") if __name__ == '__main__': import sys diff --git a/Widgets/settings.py b/Widgets/settings.py index 17ea7f6..a7820fc 100644 --- a/Widgets/settings.py +++ b/Widgets/settings.py @@ -17,12 +17,13 @@ import os import sys import time from PyQt5 import uic -from PyQt5.QtWidgets import QApplication, QLineEdit, QPushButton, QLabel +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 import logging +import can current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -31,6 +32,7 @@ current_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.dirname(current_dir)) import extras.Kuksa_Instance as kuksa_instance +from extras import config Form, Base = uic.loadUiType(os.path.join( current_dir, "../ui/Settings_Window.ui")) @@ -39,6 +41,12 @@ Form, Base = uic.loadUiType(os.path.join( Steering_Signal_Type = "Kuksa" +def create_animated_toggle(): + return AnimatedToggle( + checked_color="#4BD7D6", + pulse_checked_color="#00ffff", + ) + class settings(Base, Form): """ A class representing the settings widget of the AGL Demo Control Panel. @@ -60,31 +68,34 @@ class settings(Base, Form): """ super(self.__class__, self).__init__(parent) self.setupUi(self) - - self.SSL_toggle = AnimatedToggle( - checked_color="#4BD7D6", - pulse_checked_color="#00ffff", - ) - - self.Protocol_toggle = AnimatedToggle( - checked_color="#4BD7D6", - pulse_checked_color="#00ffff" - ) - self.CAN_Kuksa_toggle = AnimatedToggle( - checked_color="#4BD7D6", - pulse_checked_color="#00ffff" - ) + self.SSL_toggle = create_animated_toggle() + self.Protocol_toggle = create_animated_toggle() + self.CAN_Kuksa_toggle = create_animated_toggle() self.connectionStatus = self.findChild(QLabel, "connectionStatus") self.connectionLogo = self.findChild(QLabel, "connectionLogo") + list_of_configs = config.get_list_configs() + default_config_name = config.get_default_config() + + self.List_Configs_ComboBox = self.findChild(QComboBox, "List_Configs_ComboBox") + self.List_Configs_ComboBox.setItemDelegate(QStyledItemDelegate()) + self.List_Configs_ComboBox.addItems(list_of_configs) + self.List_Configs_ComboBox.setCurrentText(default_config_name) + self.List_Configs_ComboBox.currentTextChanged.connect(lambda: self.set_settings(self.List_Configs_ComboBox.currentText())) + self.IPAddrInput = self.findChild(QLineEdit, "IPAddrInput") + self.PortInput = self.findChild(QLineEdit, "PortInput") + self.TLS_Server_Name = self.findChild(QLineEdit, "TLS_Server_Name") + self.Auth_Token = self.findChild(QLineEdit, "Auth_Token") + self.CA_File = self.findChild(QLineEdit, "CA_File") self.reconnectBtn = self.findChild(QPushButton, "reconnectBtn") self.startClientBtn = self.findChild(QPushButton, "startClientBtn") + self.startClientBtn.setCheckable(True) - self.startClientBtn.clicked.connect(self.set_instance) + self.startClientBtn.clicked.connect(self.start_stop_client) self.reconnectBtn.clicked.connect(self.reconnectClient) self.SSL_toggle.clicked.connect(self.toggleSSL) self.CAN_Kuksa_toggle.clicked.connect(self.toggle_CAN_Kuksa) @@ -102,7 +113,27 @@ class settings(Base, Form): self.place_holder_toggle_2.deleteLater() self.place_holder_toggle_3.deleteLater() - self.refreshStatus() + self.set_settings(default_config_name) + + def start_stop_client(self): + if self.startClientBtn.isChecked(): + # turn button red and change icon to stop from resources + self.set_instance() + if self.client is not None: + self.startClientBtn.setStyleSheet("border: 1px solid red;") + self.startClientBtn.setIcon(QtGui.QIcon(":/Carbon_Icons/carbon_icons/stop.svg")) + self.startClientBtn.setText("Stop Client") + else: + self.startClientBtn.setChecked(False) + else: + # turn button green and change icon to start from resources + if self.client is not None: + self.client.stop() + + self.startClientBtn.setStyleSheet("border: 1px solid green;") + self.startClientBtn.setIcon(QtGui.QIcon(":/Carbon_Icons/carbon_icons/play.svg")) + self.startClientBtn.setText("Start Client") + def toggleSSL(self): """ @@ -117,7 +148,14 @@ class settings(Base, Form): """ global Steering_Signal_Type if (self.CAN_Kuksa_toggle.isChecked()): - Steering_Signal_Type = "CAN" + # check if can0 is available + try: + can_bus = can.interface.Bus(channel='can0', bustype='socketcan_native') + can_bus.shutdown() + Steering_Signal_Type = "CAN" + except: + self.CAN_Kuksa_toggle.setChecked(False) + logging.error("CAN Bus not available") else: Steering_Signal_Type = "Kuksa" @@ -132,13 +170,12 @@ class settings(Base, Form): Sets the instance of the Kuksa client. """ self.kuksa = kuksa_instance.KuksaClientSingleton.instance() - self.client = self.kuksa.get_client() - - self.kuksa_config = self.kuksa.get_config() - - self.IPAddrInput.setText(self.kuksa_config["ip"]) - self.SSL_toggle.setChecked(not self.kuksa_config["insecure"]) - self.Protocol_toggle.setChecked(self.kuksa_config["protocol"] == 'grpc') + new_config = self.make_new_config() + if (new_config is None): + logging.error("Invalid configuration") + else: + self.kuksa.reconnect(new_config, self.kuksa_token) + self.client = self.kuksa.get_client() time.sleep(2) @@ -162,7 +199,6 @@ class settings(Base, Form): if (self.client.checkConnection() == True): self.connectionStatus.setText('Connected') self.connectionLogo.setStyleSheet("background-color: green") - # change cnnection logo pixmap to connected.svf from resources self.connectionLogo.setPixmap(QtGui.QPixmap(":/Carbon_Icons/carbon_icons/connection-signal.svg")) self.client.start() return True @@ -180,23 +216,66 @@ class settings(Base, Form): """ Reconnects the client. """ - try: - self.kuksa_config["ip"] = self.IPAddrInput.text() - self.kuksa_config["insecure"] = not self.SSL_toggle.isChecked() - self.kuksa_config["protocol"] = self.get_protocol() - if self.kuksa_config["protocol"] == 'ws': - self.kuksa_config["port"] = "8090" - if self.kuksa_config["protocol"] == 'grpc': - self.kuksa_config["port"] = "55555" - self.client = self.kuksa.reconnect(self.kuksa_config) - self.client.start() - self.refreshStatus() - - self.refreshThread = RefreshThread(self) - self.refreshThread.start() - - except Exception as e: - logging.error(e) + if (self.client is not None): + try: + config = self.make_new_config() + self.client.stop() + self.client = self.kuksa.reconnect(config, self.kuksa_token) + self.client.start() + self.refreshStatus() + + self.refreshThread = RefreshThread(self) + self.refreshThread.start() + + except Exception as e: + logging.error(e) + self.set_instance() + + def make_new_config(self): + """ + Makes a new configuration using fields in the settings widget. + """ + + def validate_and_set_style(self, widget, key=None): + text = widget.text() + if text: + if os.path.exists(text): + widget.setStyleSheet("border: 1px solid #4BD7D6 ; /* light blue */") + if key: + self.new_config[key] = text + else: + self.kuksa_token = text + else: + widget.setStyleSheet("border: 1px solid red;") + return None + + new_config = {} + new_config["ip"] = self.IPAddrInput.text() + new_config["port"] = self.PortInput.text() + new_config["protocol"] = self.get_protocol() + new_config["insecure"] = not self.SSL_toggle.isChecked() + new_config["tls_server_name"] = self.TLS_Server_Name.text() if self.Protocol_toggle.isChecked() else None + validate_and_set_style(self, self.CA_File, "cacertificate") + validate_and_set_style(self, self.Auth_Token) + + return new_config + + def set_settings(self, config_name): + """ + Reloads the parameters of settings widget. + """ + new_config = config.select_config(config_name) + self.kuksa_config_name = new_config[0] + self.kuksa_config = new_config[1] + self.kuksa_token = new_config[2] + + self.IPAddrInput.setText(self.kuksa_config["ip"]) + self.PortInput.setText(self.kuksa_config["port"]) + self.SSL_toggle.setChecked(not self.kuksa_config["insecure"]) + self.Protocol_toggle.setChecked(self.kuksa_config["protocol"] == 'grpc') + self.CA_File.setText(self.kuksa_config["cacertificate"]) + self.TLS_Server_Name.setText(self.kuksa_config["tls_server_name"] if self.kuksa_config["tls_server_name"] is not None else "") + self.Auth_Token.setText(self.kuksa_token) class RefreshThread(QThread): def __init__(self, settings): diff --git a/assets/carbon_icons/chevron--down.svg b/assets/carbon_icons/chevron--down.svg new file mode 100644 index 0000000..eaedea9 --- /dev/null +++ b/assets/carbon_icons/chevron--down.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/assets/carbon_icons/chevron--up.svg b/assets/carbon_icons/chevron--up.svg new file mode 100644 index 0000000..90d9470 --- /dev/null +++ b/assets/carbon_icons/chevron--up.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/assets/carbon_icons/corner.svg b/assets/carbon_icons/corner.svg new file mode 100644 index 0000000..0dc6056 --- /dev/null +++ b/assets/carbon_icons/corner.svg @@ -0,0 +1,9 @@ + + + + + corner + + + + diff --git a/assets/carbon_icons/stop.svg b/assets/carbon_icons/stop.svg new file mode 100644 index 0000000..f252f90 --- /dev/null +++ b/assets/carbon_icons/stop.svg @@ -0,0 +1 @@ +stop diff --git a/assets/res.qrc b/assets/res.qrc index 3a04df5..a662c76 100644 --- a/assets/res.qrc +++ b/assets/res.qrc @@ -1,5 +1,9 @@ + carbon_icons/stop.svg + carbon_icons/chevron--down.svg + carbon_icons/chevron--up.svg + carbon_icons/corner.svg carbon_icons/connection-signal.svg carbon_icons/connection-signal--off.svg carbon_icons/x-axis.svg diff --git a/extras/FeedKuksa.py b/extras/FeedKuksa.py index 56e902e..cda2a30 100644 --- a/extras/FeedKuksa.py +++ b/extras/FeedKuksa.py @@ -14,12 +14,15 @@ limitations under the License. """ -import time import logging from PyQt5.QtCore import QThread +from PyQt5.QtCore import pyqtSignal from . import Kuksa_Instance as kuksa_instance +import threading class FeedKuksa(QThread): + sending_values = pyqtSignal() + finished_sending_values = pyqtSignal() """ A class to handle sending values to Kuksa. @@ -85,20 +88,25 @@ class FeedKuksa(QThread): Exception If there is an error sending values to Kuksa. """ - if self.client is not None: - if self.client.checkConnection(): - try: - if attribute is not None: - self.client.setValue(path, str(value), attribute) - else: - self.client.setValue(path, str(value)) - except Exception as e: - logging.error(f"Error sending values to kuksa {e}") - self.set_instance() - else: - logging.error("Kuksa client is not connected, try reconnecting") - self.set_instance() - else: + + if self.client is None: logging.error("Kuksa client is None, try reconnecting") - time.sleep(2) - self.set_instance() \ No newline at end of file + return + + if not self.client.checkConnection(): + logging.error("Kuksa client is not connected, try reconnecting") + threading.Thread(target=self.set_instance).start() + return + + try: + if attribute is not None: + self.sending_values.emit() + self.client.setValue(path, value, attribute) + else: + self.sending_values.emit() + self.client.setValue(path, value) + + self.finished_sending_values.emit() + except Exception as e: + logging.error(f"Error sending values to kuksa {e}") + threading.Thread(target=self.set_instance).start() \ No newline at end of file diff --git a/extras/Kuksa_Instance.py b/extras/Kuksa_Instance.py index 500e039..1ff8056 100644 --- a/extras/Kuksa_Instance.py +++ b/extras/Kuksa_Instance.py @@ -19,8 +19,6 @@ import kuksa_client as kuksa import threading import time -from extras import config - class KuksaClientSingleton: """ A singleton class that provides a single instance of KuksaClientThread. @@ -73,28 +71,11 @@ class KuksaClientSingleton: if KuksaClientSingleton._instance is not None: raise Exception("This class is a singleton!") - self.kuksa_config = config.KUKSA_CONFIG - self.ws_token = config.WS_TOKEN - self.grpc_token = config.GRPC_TOKEN - - if self.kuksa_config["protocol"] == 'ws': - self.token = self.ws_token - if self.kuksa_config["protocol"] == 'grpc': - self.token = self.grpc_token - - try: - self.client = kuksa.KuksaClientThread(self.kuksa_config) - self.client.authorize(self.token) - self.client.start() - time.sleep(2) - if not self.client.checkConnection(): - self.client = None - except Exception as e: - print(e) + self.client = None KuksaClientSingleton._instance = self - def reconnect(self, config): + def reconnect(self, config, token): """ Reconnects the client with the given configuration and token. @@ -107,18 +88,10 @@ class KuksaClientSingleton: """ if self.client: self.client.stop() - - if self.kuksa_config["protocol"] == 'ws': - self.token = self.ws_token - self.kuksa_config["port"] = "8090" - if self.kuksa_config["protocol"] == 'grpc': - self.token = self.grpc_token - self.kuksa_config["port"] = "55555" - self.client = kuksa.KuksaClientThread(self.kuksa_config) - self.client.authorize(self.token) + self.client = kuksa.KuksaClientThread(config) + self.client.authorize(token) self.client.start() - return self.client def get_client(self): """ diff --git a/extras/UI_Handeler.py b/extras/UI_Handeler.py index 2bfcfc4..261df94 100644 --- a/extras/UI_Handeler.py +++ b/extras/UI_Handeler.py @@ -24,16 +24,30 @@ from PyQt5.QtWidgets import QDesktopWidget import logging import json +from . import FeedKuksa as feed_kuksa from . import Kuksa_Instance as kuksa_instance # Global variables subscribed = False should_execute_callback = True +block_subscription_updates = False class UI_Handeler(MainWindow): """ This class handles the UI of the AGL Demo Control Panel application. """ + def __init__(self): + self.feed_kuksa = feed_kuksa.FeedKuksa() + self.feed_kuksa.sending_values.connect(self.block_updates) + self.feed_kuksa.finished_sending_values.connect(self.unblock_updates) + + def block_updates(self): + global block_subscription_updates + block_subscription_updates = True + + def unblock_updates(self): + global block_subscription_updates + block_subscription_updates = False def Hide_Navbar(self, bool_arg): """ @@ -143,9 +157,10 @@ class UI_Handeler(MainWindow): Args: - data: The data received from the signal. """ - global should_execute_callback - if should_execute_callback is False: + global block_subscription_updates + if block_subscription_updates: return + IC_Page = self.stackedWidget.widget(1) HVAC_Page = self.stackedWidget.widget(2) diff --git a/extras/config.ini b/extras/config.ini new file mode 100644 index 0000000..0f64a4f --- /dev/null +++ b/extras/config.ini @@ -0,0 +1,48 @@ +[default] +preferred-config=AGL-kuksa-val-server + +# [cutom-config-template] +# ip= +# port= +# protocol= # ws/grpc -> kuksa-val-server, grpc -> databroker +# insecure= # Note: Use insecure mode only if server is also running in insecure mode +# cacert= +# token= +# tls_server_name= + +[kuksa-val-server] +ip=localhost +port=8090 +protocol=ws +insecure=false +token=default +tls_server_name= + + +[databroker] +ip=localhost +port=55555 +protocol=grpc +insecure=false +token=default +tls_server_name=Server + + +[AGL-kuksa-val-server] +ip=localhost +port=8090 +protocol=ws +insecure=false +cacert=default +token=default +tls_server_name= + + +[AGL-databroker] +ip=10.42.0.95 +port=55555 +protocol=grpc +insecure=false +cacert=default +token=default +tls_server_name=Server diff --git a/extras/config.py b/extras/config.py index 3309b71..2b92342 100644 --- a/extras/config.py +++ b/extras/config.py @@ -16,19 +16,96 @@ import os import platform +from configparser import ConfigParser python_version = f"python{'.'.join(platform.python_version_tuple()[:2])}" -CA = os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/cert/CA.pem")) +def check_paths(*paths): + return {path: os.path.exists(path) for path in paths} -KUKSA_CONFIG = { - "ip": '127.0.0.1', - "port": "55555", - 'protocol': 'grpc', - 'insecure': False, - 'cacertificate': CA, - 'tls_server_name': "Server", -} +CONFIG_PATHS = check_paths( + "/etc/agl-demo-control-panel.ini", + os.path.join(os.path.expanduser("~"), ".local/share/agl-demo-control-panel/config.ini"), + os.path.abspath(os.path.join(os.path.dirname(__file__), 'config.ini')) +) -WS_TOKEN = os.path.join(os.path.expanduser("~"), f".local/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token") -GRPC_TOKEN = os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/token/grpc/actuate-provide-all.token")) +CA_PATHS = check_paths( + "/etc/kuksa-val/CA.pem", + f"/usr/lib/{python_version}/site-packages/kuksa_certificates/CA.pem", + os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/cert/CA.pem")) +) + +WS_TOKEN_PATHS = check_paths( + f"/usr/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token", + os.path.join(os.path.expanduser("~"), f".local/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token") +) + +GRPC_TOKEN_PATHS = check_paths( + f"/usr/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token", + os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/token/grpc/actuate-provide-all.token")) +) + +config = ConfigParser() +config_path = next((path for path, exists in CONFIG_PATHS.items() if exists), None) +if config_path: + config.read(config_path) + +CA_PATH = next((path for path, exists in CA_PATHS.items() if exists), None) +WS_TOKEN = next((path for path, exists in WS_TOKEN_PATHS.items() if exists), None) +GRPC_TOKEN = next((path for path, exists in GRPC_TOKEN_PATHS.items() if exists), None) + +KUKSA_CONFIG = {} +KUKSA_TOKEN = None + +def select_config(preferred_config): + """ + Selects a configuration from the config.ini file based on the preferred_config parameter. + + Args: + preferred_config (str): The name of the configuration section to select. + + Returns: + Tuple[str, Dict[str, Union[str, bool]], str]: A tuple containing the name of the selected configuration section, + a dictionary containing the configuration options for the selected section, and the token to use for the selected + protocol. + """ + global KUKSA_CONFIG, KUKSA_TOKEN + KUKSA_CONFIG.clear() + + if config.has_section(preferred_config): + KUKSA_CONFIG['ip'] = config[preferred_config]['ip'] + KUKSA_CONFIG['port'] = config[preferred_config]['port'] + KUKSA_CONFIG['protocol'] = config[preferred_config]['protocol'] + KUKSA_CONFIG['insecure'] = False if config[preferred_config]['insecure'] == 'false' else True + + if config.has_option(preferred_config, 'cacert'): + KUKSA_CONFIG['cacertificate'] = config[preferred_config]['cacert'] if os.path.exists(config[preferred_config]['cacert']) else CA_PATH + else: + KUKSA_CONFIG['cacertificate'] = None + + KUKSA_CONFIG['tls_server_name'] = config[preferred_config]['tls_server_name'] + + if config.has_option(preferred_config, 'token'): + if config[preferred_config]['token'] == 'default': + KUKSA_TOKEN = get_default_token(KUKSA_CONFIG['protocol']) + elif os.path.exists(config[preferred_config]['token']): + KUKSA_TOKEN = config[preferred_config]['token'] + else: + ValueError(f"Token file {config[preferred_config]['token']} not found") + else: + raise ValueError(f"Config section {preferred_config} not found in config.ini") + + return preferred_config, KUKSA_CONFIG , KUKSA_TOKEN + +def get_list_configs(): + return config.sections()[1:] + +def get_default_config(): + defaultConfigName = config.get('default', 'preferred-config') + return defaultConfigName + +def get_default_token(protocol): + if protocol == 'grpc': + return GRPC_TOKEN + else: + return WS_TOKEN \ No newline at end of file diff --git a/main.py b/main.py index d832789..c4185f6 100644 --- a/main.py +++ b/main.py @@ -52,7 +52,7 @@ class MainWindow(Base, Form): self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.setStyle(QtWidgets.QStyleFactory.create('Fusion')) - + #self.resize(1400,840) self.headerContainer = self.findChild(QWidget, 'headerContainer') self.headerContainer.DoubleClickMaximize = lambda: UI_Handeler.toggleMaximized(self) self.headerContainer.mouseMoveEvent = lambda event: UI_Handeler.moveWindow(self, event) @@ -96,7 +96,7 @@ class MainWindow(Base, Form): self.stop_thread_signal.connect(self.stackedWidget.widget(0).feed_kuksa.stop) - self.stackedWidget.setCurrentIndex(0) + self.stackedWidget.setCurrentIndex(0) self.dashboardButton.setChecked(True) UI_Handeler.Hide_Navbar(self,bool_arg=False) @@ -105,6 +105,24 @@ class MainWindow(Base, Form): self.current_page = self.stackedWidget.currentIndex() + self.centralwidget = self.findChild(QWidget, 'centralwidget') + self.size_grip = QtWidgets.QSizeGrip(self) + self.size_grip.setFixedSize(20, 20) + #self.size_grip.setStyleSheet("QSizeGrip { background-color: transparent; }") + self.size_grip.setStyleSheet(""" + QSizeGrip { + background-color: transparent; + background-image: url(:/Carbon_Icons/carbon_icons/corner.svg); + background-repeat: no-repeat; + background-position: center; + border: none; + } + """) + self.centralwidget.layout().addWidget(self.size_grip, 0, Qt.AlignBottom | Qt.AlignRight) + + def VSS_callback(self,data): + pass + def handleTileClicked(self): """ Handles the tile clicked signal from the Dashboard object. diff --git a/ui/HVAC.ui b/ui/HVAC.ui index abee74f..8779962 100644 --- a/ui/HVAC.ui +++ b/ui/HVAC.ui @@ -6,8 +6,8 @@ 0 0 - 713 - 527 + 815 + 575 @@ -66,7 +66,7 @@ QSlider::sub-page:vertical { background-color: #131313 ; /* black */ height: 20px; - width: 18px; + width: 28px; margin: 2px; border: 1px solid #6C6C85 ; /* pastel purple */ border-radius: 8px; @@ -74,7 +74,7 @@ QSlider::sub-page:vertical { QSlider::groove:vertical { border-radius: 8px; - width: 18px; + width: 28px; margin: 2px; border: 1px solid #6C6C85 ; /* pastel purple */ background-color: #4BD7D6 ; /* light blue */ @@ -190,44 +190,6 @@ QListWidget::item:hover { QFrame::Raised - - - - - 0 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - 75 - true - true - - - - HVAC - - - - - - @@ -238,8 +200,8 @@ QListWidget::item:hover { 0 0 - 697 - 409 + 799 + 517 @@ -248,6 +210,9 @@ QListWidget::item:hover { Qt::Vertical + + QSizePolicy::Fixed + 20 @@ -271,12 +236,28 @@ QListWidget::item:hover { QFrame::Raised - - + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + 0 - 0 + 50 @@ -285,69 +266,15 @@ QListWidget::item:hover { QFrame::Raised - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + + + - + 0 0 - - - 0 - 152 - - - - - 60 - 152 - - 75 @@ -355,83 +282,47 @@ QListWidget::item:hover { true - - Qt::StrongFocus - - - Qt::LeftToRight - - - false - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed - - - false - - - QAbstractItemView::DragOnly - - - QAbstractItemView::ContiguousSelection - - - Qt::ElideMiddle - - - QAbstractItemView::ScrollPerPixel - - - QListView::Snap - - - QListView::Adjust - - - QListView::SinglePass - - - 1 - - - QListView::ListMode - - - true - - - Qt::AlignCenter - - - - - - - - - :/Images/Images/HMI_HVAC_Fan_Icon.svg + HVAC - - + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 75 @@ -440,78 +331,223 @@ QListWidget::item:hover { - Right Controls + Left Controls - - + + - Qt::Horizontal + Qt::Vertical QSizePolicy::Fixed - 40 - 20 + 20 + 40 - - - - - 40 - 0 - - + + Qt::Vertical - - - - - - + + QSizePolicy::Fixed - - - :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg + + + 20 + 20 + - + + + + + + Qt::Horizontal + + 40 - 40 + 20 - + - - - - + + + + Qt::Horizontal - - - :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg + + QSizePolicy::Fixed - + 40 - 40 + 20 + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg + + + + 40 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 152 + + + + + 60 + 152 + + + + + 75 + true + true + + + + Qt::StrongFocus + + + Qt::LeftToRight + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + false + + + QAbstractItemView::DragOnly + + + QAbstractItemView::SingleSelection + + + Qt::ElideMiddle + + + QAbstractItemView::ScrollPerPixel + + + QListView::Snap + + + false + + + QListView::Adjust + + + QListView::SinglePass + + + 1 + + + QListView::ListMode + + + true + + + true + + + Qt::AlignCenter + + + + + + + + + + + :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg + + + + 40 + 40 + + + + + - - + + Qt::Vertical + + QSizePolicy::Preferred + 20 @@ -520,27 +556,101 @@ QListWidget::item:hover { + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 40 + 0 + + + + Qt::Vertical + + + false + + + false + + + QSlider::NoTicks + + + 0 + + + + + + + + + + :/Images/Images/HMI_HVAC_Fan_Icon.svg + + + false + + + Qt::AlignCenter + + + + + + - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - + + Qt::Horizontal @@ -555,8 +665,8 @@ QListWidget::item:hover { - - + + 0 @@ -569,42 +679,14 @@ QListWidget::item:hover { QFrame::Raised - - - - - - 0 - 0 - - - - - 40 - 0 - - + + + Qt::Vertical - - false - - - false - - - QSlider::NoTicks - - - 0 - - - - - - - Qt::Vertical + + QSizePolicy::Preferred @@ -614,44 +696,14 @@ QListWidget::item:hover { - - - - - - - :/Images/Images/HMI_HVAC_Fan_Icon.svg - - - false - - - Qt::AlignCenter - - - - - - - - - - - :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg - - - - 40 - 40 - - - - - - + + Qt::Horizontal + + QSizePolicy::Fixed + 40 @@ -660,125 +712,80 @@ QListWidget::item:hover { - - - - - 0 - 0 - - - - - 0 - 152 - - - - - 60 - 152 - - - - - 75 - true - true - - - - Qt::StrongFocus - - - Qt::LeftToRight - - - false - + + - QFrame::NoFrame + QFrame::StyledPanel - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - - - QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed - - - false - - - QAbstractItemView::DragOnly - - - QAbstractItemView::SingleSelection - - - Qt::ElideMiddle - - - QAbstractItemView::ScrollPerPixel - - - QListView::Snap - - - false - - - QListView::Adjust - - - QListView::SinglePass - - - 1 - - - QListView::ListMode - - - true - - - true - - - Qt::AlignCenter - + QFrame::Raised + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 40 + 0 + + + + Qt::Vertical + + + + + + + + + + :/Images/Images/HMI_HVAC_Fan_Icon.svg + + + + - - + + - Qt::Vertical + Qt::Horizontal QSizePolicy::Fixed - 20 + 40 20 - - + + Qt::Horizontal + + QSizePolicy::Fixed + 40 @@ -787,25 +794,24 @@ QListWidget::item:hover { - - - - + + + + Qt::Vertical - - - :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg + + QSizePolicy::Fixed - + - 40 - 40 + 20 + 20 - + - - + + 75 @@ -814,45 +820,167 @@ QListWidget::item:hover { - Left Controls + Right Controls - - + + - Qt::Horizontal + Qt::Vertical QSizePolicy::Fixed - 40 - 20 + 20 + 40 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + :/Carbon_Icons/carbon_icons/temperature--frigid.svg:/Carbon_Icons/carbon_icons/temperature--frigid.svg + + + + 40 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 152 + + + + + 60 + 152 + + + + + 75 + true + true + + + + Qt::StrongFocus + + + Qt::LeftToRight + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + false + + + QAbstractItemView::DragOnly + + + QAbstractItemView::ContiguousSelection + + + Qt::ElideMiddle + + + QAbstractItemView::ScrollPerPixel + + + QListView::Snap + + + QListView::Adjust + + + QListView::SinglePass + + + 1 + + + QListView::ListMode + + + true + + + Qt::AlignCenter + + + + + + + + + + + :/Carbon_Icons/carbon_icons/temperature--hot.svg:/Carbon_Icons/carbon_icons/temperature--hot.svg + + + + 40 + 40 + + + + + + + - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - @@ -865,6 +993,9 @@ QListWidget::item:hover { Qt::Vertical + + QSizePolicy::Fixed + 20 diff --git a/ui/IC.ui b/ui/IC.ui index 725a2b3..4452564 100644 --- a/ui/IC.ui +++ b/ui/IC.ui @@ -6,8 +6,8 @@ 0 0 - 724 - 720 + 920 + 800 @@ -42,14 +42,15 @@ QPushButton:pressed { } QSlider::groove:horizontal { + background-color: #131313 ; /* black */ border: 1px solid #6C6C85 ; /* pastel purple */ - height: 15px; + height: 28px; border-radius: 8px; } QSlider::sub-page:horizontal { background-color: #4BD7D6 ; /* light blue */ - height: 15px; + height: 28px; border-radius: 5px; } @@ -66,16 +67,16 @@ QSlider::handle:horizontal { QSlider::sub-page:vertical { background-color: #131313 ; /* black */ height: 20px; - width: 18px; - margin: 2px; + width: 28px; + margin: 4px; border: 1px solid #6C6C85 ; /* pastel purple */ border-radius: 8px; } QSlider::groove:vertical { border-radius: 8px; - width: 18px; - margin: 2px; + width: 28px; + margin: 4px; border: 1px solid #6C6C85 ; /* pastel purple */ background-color: #4BD7D6 ; /* light blue */ } @@ -152,7 +153,7 @@ QLCDNumber { - + 0 0 @@ -164,6 +165,32 @@ QLCDNumber { QFrame::Raised + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -174,42 +201,33 @@ QLCDNumber { 0 0 - 664 - 652 + 684 + 782 - - + + Qt::Vertical + + QSizePolicy::Fixed + 20 - 40 + 20 - - - - - 0 - 0 - - + + 0 - 0 - - - - - 16777215 - 150 + 50 @@ -218,139 +236,70 @@ QLCDNumber { QFrame::Raised - - - - - - - - - :/Images/Images/right.png:/Images/Images/right.png - - - - 60 - 60 - - + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + Open Sans Extrabold + 75 + true + true + + + + Instrument Cluster + + + + - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - false - - - false + + + + + 75 + true + true + - - - - - :/Images/Images/left.png:/Images/Images/left.png - - - - 60 - 60 - - - - false - - - false + Demo Mode - - + + - - - :/Images/Images/hazard.png:/Images/Images/hazard.png - - - - 60 - 60 - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - 0 - 0 - - + + 0 - 200 - - - - - 16777215 - 150 + 80 @@ -359,200 +308,255 @@ QLCDNumber { QFrame::Raised - - - + + + Qt::Horizontal - - QSizePolicy::Fixed - - 10 + 167 20 - - - - QFrame::NoFrame - - - 4 - - - QLCDNumber::Flat - - - - - + + - 60 - 0 + 50 + 50 - true + Open Sans + 20 + 75 + false + true - - 0 + + P - - Qt::Vertical + + + 16 + 16 + - - false + + true - + false - - QSlider::NoTicks - - - - + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + - 60 - 0 + 40 + 20 - - Qt::Vertical - - + - - + + + + + 50 + 50 + + Open Sans + 20 75 - true + false true - Speed (Kmph) + R + + + true - - + + - Qt::Vertical + Qt::Horizontal - + + QSizePolicy::Fixed + + + + 40 + 20 + + + - - - - - 0 - 0 - + + + + + 50 + 50 + - 12 + Open Sans + 20 + 75 + false + true - - QFrame::NoFrame - - - - - :/Carbon_Icons/carbon_icons/rain-drop.svg + N - - false + + true - - + + - Qt::Vertical + Qt::Horizontal QSizePolicy::Fixed - 20 - 10 + 40 + 20 - - + + + + + 50 + 50 + + - 50 + Open Sans + 20 + 75 false - false + true - - Qt::LeftToRight - - - QFrame::NoFrame - - - false - - - 3 + + D - - QLCDNumber::Flat + + true - - - + + + + Qt::Horizontal + + - 0 - 60 + 168 + 20 - - - 50 - false - - - - 240 - - - Qt::Horizontal + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 150 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + - - QSlider::NoTicks + + + :/Images/Images/right.png:/Images/Images/right.png - - 0 + + + 60 + 60 + - - + + Qt::Horizontal @@ -567,8 +571,8 @@ QLCDNumber { - - + + Qt::Horizontal @@ -583,65 +587,57 @@ QLCDNumber { - - - - - 0 - 60 - + + + + false - - Qt::Horizontal + + false - - - - - - Qt::Horizontal + + - - QSizePolicy::Fixed + + + :/Images/Images/left.png:/Images/Images/left.png - + - 10 - 20 + 60 + 60 - - - - - - + + false - - :/Carbon_Icons/carbon_icons/temperature--water.svg + + false - - - - - Open Sans - 75 - true - true - - + + - Engine RPM + + + + + :/Images/Images/hazard.png:/Images/Images/hazard.png + + + + 60 + 60 + - - + + Qt::Vertical @@ -667,6 +663,12 @@ QLCDNumber { + + + 0 + 0 + + 0 @@ -697,31 +699,27 @@ QLCDNumber { - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - + + + + + 0 + 0 + + 0 - 80 + 200 + + + + + 16777215 + 150 @@ -730,56 +728,106 @@ QLCDNumber { QFrame::Raised - - - - - Qt::Horizontal - - - - 167 - 20 - - - - - - - - - 50 - 50 - - + + + Open Sans - 20 75 - false + true true - P + Engine RPM - - - 16 - 16 - + + + + + + + 0 + 0 + - - true + + + 50 + false + false + - + + Qt::LeftToRight + + + QFrame::NoFrame + + false + + 3 + + + QLCDNumber::Flat + - - + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 4 + + + + + + + + :/Carbon_Icons/carbon_icons/temperature--water.svg + + + + + + + + 60 + 0 + + + + Qt::Vertical + + + + + + + + Qt::Horizontal @@ -788,39 +836,30 @@ QLCDNumber { - 40 + 10 20 - - - - - 50 - 50 - - - - - Open Sans - 20 - 75 - false - true - + + + + Qt::Vertical - - R + + QSizePolicy::Fixed - - true + + + 20 + 10 + - + - - + + Qt::Horizontal @@ -829,39 +868,34 @@ QLCDNumber { - 40 + 10 20 - - + + - 50 - 50 + 0 + 60 - - - Open Sans - 20 - 75 - false - true - - - - N + + Qt::Horizontal - - true + + + + + + Qt::Vertical - - + + Qt::Horizontal @@ -870,168 +904,178 @@ QLCDNumber { - 40 + 20 20 - - - - - 50 - 50 - + + + + + 0 + 0 + + + + 50 + false + + + + QFrame::NoFrame + + + 4 + + + QLCDNumber::Flat + + + + + Open Sans - 20 75 - false + true true - D + Speed (Kmph) - - true + + + + + + + 0 + 60 + + + + + 50 + false + + + + 240 + + + Qt::Horizontal + + + QSlider::NoTicks + + + 0 - - + + Qt::Horizontal + + QSizePolicy::Fixed + - 168 + 20 20 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 4 + + + + + + 60 + 0 + + + + + true + + + + 0 + + + Qt::Vertical + + + false + + + false + + + QSlider::NoTicks + + + + + + + + 0 + 0 + + + + + 12 + + + + QFrame::NoFrame + + + + + + :/Carbon_Icons/carbon_icons/rain-drop.svg + + + false + + + + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - Open Sans Extrabold - 75 - true - true - - - - Instrument Cluster - - - - - - - - - - - 75 - true - true - - - - Demo Mode - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - diff --git a/ui/Settings_Window.ui b/ui/Settings_Window.ui index 477fa40..e1a6b81 100644 --- a/ui/Settings_Window.ui +++ b/ui/Settings_Window.ui @@ -16,7 +16,7 @@ *{ border: none; - background-color: transparent; + /* background-color: transparent; */ background: none; padding: 0; margin: 0; @@ -33,6 +33,7 @@ QPushButton{ padding: 5px 10px; border: 1px solid #4BD7D6 ; /* light blue */ border-radius: 10px; + margin: 3px; } QPushButton:pressed { @@ -44,6 +45,48 @@ QPushButton:pressed { padding: 5px 10px; border: 1px solid #4BD7D6 ; /* light blue */ border-radius: 10px; + margin: 3px; +} + +QComboBox{ + background-color: transparent; + padding: 5px 10px; + border: 1px solid #4BD7D6 ; /* light blue */ + border-radius: 10px; + margin: 3px; +} + +QComboBox::drop-down { + image: url(:/Carbon_Icons/carbon_icons/chevron--down.svg); +} + +QComboBox::down-arrow { + image: url(:/Carbon_Icons/carbon_icons/chevron--down.svg); +} + +QComboBox::up-arrow { + image: url(:/Carbon_Icons/carbon_icons/chevron--up.svg); +} + +QComboBox QAbstractItemView { + color: #4BD7D6; /* light blue */ + background-color: #131313; /* black */ + border: 1px solid #4BD7D6; /* light blue */ + border-radius: 10px; /* rounded corners */ +} + +QComboBox QAbstractItemView::item { + color: #4BD7D6; /* light blue */ + background-color: #131313; /* black */ + border: 1px solid #4BD7D6; /* light blue */ + border-radius: 10px; /* rounded corners */ + padding: 5px 10px; + margin: 3px; +} + +QComboBox QAbstractItemView::item:selected { + background-color: #6C6C85 ; /* pastel purple */ + border-radius: 10px; /* rounded corners */ } QCheckBox { @@ -67,11 +110,74 @@ QCheckBox:disabled { QCheckBox:indicator:disabled { background-color: #cccccc; /* Grayed out background */ +} + +#divider_1{ + background-color: #00ffff; /* Neon blue */ + border: 1px solid; +} +#divider_2{ + background-color: #00ffff; /* Neon blue */ + border: 1px solid; } - + + + + + 75 + true + true + + + + Page Settings + + + 6 + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + 75 + true + true + + + + Client Settings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + Qt::Vertical @@ -84,80 +190,88 @@ QCheckBox:indicator:disabled { - - + + - Qt::Horizontal + Qt::Vertical + + + QSizePolicy::Expanding - 40 - 20 + 20 + 40 - - + + + + + 0 + 0 + + QFrame::StyledPanel QFrame::Raised - - - + + + + + + 0 + 0 + + - + Start client - - :/Carbon_Icons/carbon_icons/connection-signal--off.svg + + + :/Carbon_Icons/carbon_icons/play.svg:/Carbon_Icons/carbon_icons/play.svg - - - - - - IP Address * + + + 30 + 30 + - - - - Default: WS - + + - + Reconnect - - - - - - Default: WS + + + :/Carbon_Icons/carbon_icons/renew.svg:/Carbon_Icons/carbon_icons/renew.svg - - Protocol + + + 30 + 30 + - - + + - grpc + - - - - - - Status + + :/Carbon_Icons/carbon_icons/connection-signal--off.svg - + @@ -170,124 +284,14 @@ QCheckBox:indicator:disabled { - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - :/Carbon_Icons/carbon_icons/security-services.svg - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Default: Secure - - - Secure Mode - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - ws - - - - - - - Default: localhost - - - - - - - Default: Secure - + + - - - - false + Status - + Qt::Vertical @@ -306,76 +310,21 @@ QCheckBox:indicator:disabled { - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Start client - - - - :/Carbon_Icons/carbon_icons/play.svg:/Carbon_Icons/carbon_icons/play.svg - - - - 30 - 30 - - - - - - - - Reconnect - - - - :/Carbon_Icons/carbon_icons/renew.svg:/Carbon_Icons/carbon_icons/renew.svg - - - - 30 - 30 - - - - - - - - - + + - Qt::Vertical - - - QSizePolicy::Expanding + Qt::Horizontal - 20 - 40 + 40 + 20 - - + + Qt::Horizontal @@ -387,12 +336,12 @@ QCheckBox:indicator:disabled { - + - 300 - 300 + 0 + 0 @@ -402,7 +351,21 @@ QCheckBox:indicator:disabled { QFrame::Raised - + + + + HVAC + + + + + + + + + + + @@ -419,25 +382,39 @@ QCheckBox:indicator:disabled { - - + + + + Instrument Cluster + + + + + + + Steering Controls + + + + + - - - :/Carbon_Icons/carbon_icons/view.svg:/Carbon_Icons/carbon_icons/view.svg + + :/Carbon_Icons/carbon_icons/x-axis.svg - - - 30 - 30 - + + + + + + Kuksa - - + + @@ -453,14 +430,7 @@ QCheckBox:indicator:disabled { - - - - Steering Controls - - - - + @@ -485,24 +455,34 @@ QCheckBox:indicator:disabled { - - + + - Page Settings + CAN - - + + - HVAC + + + + + :/Carbon_Icons/carbon_icons/view.svg:/Carbon_Icons/carbon_icons/view.svg + + + + 30 + 30 + - - + + - + 0 0 @@ -517,24 +497,17 @@ QCheckBox:indicator:disabled { - :/Carbon_Icons/carbon_icons/meter.svg + :/Images/Images/steering-wheel.svg true - - - - Instrument Cluster - - - - - + + - + 0 0 @@ -549,44 +522,186 @@ QCheckBox:indicator:disabled { - :/Images/Images/steering-wheel.svg + :/Carbon_Icons/carbon_icons/meter.svg true - - + + + + + + + false + + + false + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + - CAN + Port - - + + + + Default: WS + - - + + + + + - Kuksa + Default Config - - + + + + IP Address + + + + + + + Default: Secure + + + Secure Mode + + + + + + + + + + Auth Token + + + + + + + + + + + 75 + true + true + + + + ws + + + + + + + TLS Server Name + + + + + + + Default: Secure + + + + + + false + + + + + + + Default: WS + + + Protocol + + + + + + + + - :/Carbon_Icons/carbon_icons/x-axis.svg + :/Carbon_Icons/carbon_icons/security-services.svg + + + + + 75 + true + true + + + + grpc + + + + + + + CA.pem File + + + + + + diff --git a/ui/SteeringControls.ui b/ui/SteeringControls.ui index c46a00d..6d4a4d2 100644 --- a/ui/SteeringControls.ui +++ b/ui/SteeringControls.ui @@ -6,8 +6,8 @@ 0 0 - 1388 - 793 + 1034 + 600 @@ -16,13 +16,13 @@ *{ border: none; + border-radius: 8px; background-color: transparent; - background: none; + background: none; padding: 0; margin: 0; color: #fff; } - QPushButton { background-color: #6C6C85 ; /* pastel purple */ padding: 50px 50px; @@ -67,12 +67,216 @@ QPushButton:checked { - + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 200 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + :/Carbon_Icons/carbon_icons/skip--forward--filled.svg:/Carbon_Icons/carbon_icons/skip--forward--filled.svg + + + + 45 + 45 + + + + + + + + + + + + :/Carbon_Icons/carbon_icons/volume--down--filled--alt.svg:/Carbon_Icons/carbon_icons/volume--down--filled--alt.svg + + + + 45 + 45 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 75 + true + true + + + + MODE + + + + 45 + 45 + + + + false + + + + + + + + + + + :/Carbon_Icons/carbon_icons/skip--back--filled.svg:/Carbon_Icons/carbon_icons/skip--back--filled.svg + + + + 45 + 45 + + + + + + + + + + + + :/Carbon_Icons/carbon_icons/volume--up--filled--alt.svg:/Carbon_Icons/carbon_icons/volume--up--filled--alt.svg + + + + 45 + 45 + + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + :/Carbon_Icons/carbon_icons/information.svg:/Carbon_Icons/carbon_icons/information.svg + + + + 45 + 45 + + + + + + + + + + + + :/Carbon_Icons/carbon_icons/volume--mute--filled.svg:/Carbon_Icons/carbon_icons/volume--mute--filled.svg + + + + 45 + 45 + + + + + + + + + + + + + + 0 + 0 + + - 500 - 500 + 0 + 0 @@ -97,10 +301,10 @@ QPushButton:checked { 0 - + - + 0 0 @@ -114,7 +318,7 @@ QPushButton:checked { - 200 + 250 250 @@ -123,20 +327,7 @@ QPushButton:checked { - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + @@ -204,10 +395,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 + + false + @@ -240,10 +434,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 + + false + @@ -264,10 +461,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 + + false + @@ -281,14 +481,20 @@ QPushButton:checked { - 50 - 50 + 45 + 45 + + + 0 + 0 + + 75 @@ -305,10 +511,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 + + false + @@ -333,8 +542,8 @@ QPushButton:checked { - - + + Qt::Horizontal @@ -346,8 +555,27 @@ QPushButton:checked { - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 0 + 0 + + QFrame::StyledPanel @@ -355,7 +583,7 @@ QPushButton:checked { QFrame::Raised - + @@ -366,13 +594,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 - + @@ -383,13 +611,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 - + @@ -400,13 +628,13 @@ QPushButton:checked { - 50 - 50 + 45 + 45 - + @@ -417,8 +645,8 @@ QPushButton:checked { - 50 - 50 + 45 + 45 @@ -426,210 +654,27 @@ QPushButton:checked { - - + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 200 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - :/Carbon_Icons/carbon_icons/volume--up--filled--alt.svg:/Carbon_Icons/carbon_icons/volume--up--filled--alt.svg - - - - 50 - 50 - - - - - - - - - - - - :/Carbon_Icons/carbon_icons/skip--back--filled.svg:/Carbon_Icons/carbon_icons/skip--back--filled.svg - - - - 50 - 50 - - - - - - - - - 0 - 70 - - - - - 75 - true - true - - - - MODE - - - - 50 - 50 - - - - - - - - - - - - :/Carbon_Icons/carbon_icons/skip--forward--filled.svg:/Carbon_Icons/carbon_icons/skip--forward--filled.svg - - - - 50 - 50 - - - - - - - - - - - - :/Carbon_Icons/carbon_icons/volume--down--filled--alt.svg:/Carbon_Icons/carbon_icons/volume--down--filled--alt.svg - - - - 50 - 50 - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 40 - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - :/Carbon_Icons/carbon_icons/information.svg:/Carbon_Icons/carbon_icons/information.svg - - - - 50 - 50 - - - - - - - - - - - - :/Carbon_Icons/carbon_icons/volume--mute--filled.svg:/Carbon_Icons/carbon_icons/volume--mute--filled.svg - - - - 50 - 50 - - - - - - - - - - - - + + Qt::Vertical + + QSizePolicy::Expanding + 20 @@ -638,17 +683,6 @@ QPushButton:checked { - - - - - 0 - 70 - - - - - -- cgit 1.2.3-korg