feat(ui): polish About & Help tabs; theme-driven styles
About: modern card, clickable mail/URL (TextBrowserInteraction + openExternalLinks), single-line values, link color via palette; layout reuse to avoid warnings. Help: scrollable card; moved all styling to theme QSS; added Quick Start, Tips, Warnings, Troubleshooting sections. Theme: added HELP/ABOUT blocks for light & dark; cast font sizes to int to prevent light-mode crashes; consolidated #aboutCard rules; link colors per theme. Fix: removed setLayout(None) and avoided re-adding layouts to the same widget.main
parent
0012e5502c
commit
5d35b9a34d
|
|
@ -11,7 +11,7 @@ from PyQt6.QtWidgets import (
|
|||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTabWidget,
|
||||
QGroupBox, QFormLayout, QLineEdit, QPushButton, QLabel, QSpacerItem,
|
||||
QSizePolicy, QGridLayout, QMessageBox, QComboBox, QPlainTextEdit,
|
||||
QCheckBox, QFileDialog, QLayout, QFrame, QSizePolicy, QGraphicsOpacityEffect, QVBoxLayout, QTextBrowser, QScrollArea
|
||||
QCheckBox, QFileDialog, QLayout, QFrame, QSizePolicy, QGraphicsOpacityEffect, QVBoxLayout, QTextBrowser, QScrollArea, QGraphicsDropShadowEffect
|
||||
)
|
||||
from PyQt6.QtSvgWidgets import QSvgWidget
|
||||
from google.protobuf.json_format import MessageToDict
|
||||
|
|
@ -104,110 +104,62 @@ class MainWindow(QMainWindow):
|
|||
self.load_settings()
|
||||
self._apply_theme()
|
||||
|
||||
|
||||
def setup_help_ui(self):
|
||||
"""
|
||||
Polished Help page:
|
||||
Help page (theme-driven):
|
||||
- Card-style container with title
|
||||
- Sections: Quick Start, Warnings, Troubleshooting, Shortcuts
|
||||
- Colored callouts for warnings/tips
|
||||
- Scrollable if content grows
|
||||
- Sections: Quick Start, Tips, Warnings, Troubleshooting
|
||||
- Scrollable host
|
||||
"""
|
||||
# Clear existing layout
|
||||
def clear_layout(w: QWidget):
|
||||
lay = w.layout()
|
||||
if not lay: return
|
||||
while lay.count():
|
||||
it = lay.takeAt(0)
|
||||
if it.widget(): it.widget().deleteLater()
|
||||
elif it.layout():
|
||||
while it.layout().count():
|
||||
sub = it.layout().takeAt(0)
|
||||
if sub.widget(): sub.widget().deleteLater()
|
||||
it.layout().deleteLater()
|
||||
lay.deleteLater()
|
||||
|
||||
clear_layout(self.help_tab)
|
||||
# get or create root layout (never replace/delete the layout itself)
|
||||
root = self.help_tab.layout()
|
||||
if root is None:
|
||||
root = QVBoxLayout()
|
||||
root.setContentsMargins(12, 12, 12, 12)
|
||||
root.setSpacing(10)
|
||||
self.help_tab.setLayout(root)
|
||||
else:
|
||||
# clear previous contents
|
||||
while root.count():
|
||||
it = root.takeAt(0)
|
||||
w = it.widget()
|
||||
if w:
|
||||
w.setParent(None)
|
||||
w.deleteLater()
|
||||
|
||||
root = QVBoxLayout(self.help_tab)
|
||||
root.setContentsMargins(12, 12, 12, 12)
|
||||
root.setSpacing(10)
|
||||
|
||||
# Scroll area so long help stays usable
|
||||
# scroll host
|
||||
scroll = QScrollArea()
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll.setFrameShape(QFrame.Shape.NoFrame)
|
||||
|
||||
host = QWidget()
|
||||
scroll_lay = QVBoxLayout(host)
|
||||
scroll_lay.setContentsMargins(0, 0, 0, 0)
|
||||
scroll_lay.setSpacing(12)
|
||||
host_lay = QVBoxLayout(host)
|
||||
host_lay.setContentsMargins(0, 0, 0, 0)
|
||||
host_lay.setSpacing(12)
|
||||
|
||||
# Card container
|
||||
# card (styled by theme via objectNames)
|
||||
card = QFrame()
|
||||
card.setObjectName("helpCard")
|
||||
card.setStyleSheet("""
|
||||
#helpCard {
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 12px;
|
||||
}
|
||||
QLabel.title {
|
||||
color: #eaeaea;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
QLabel.subtitle {
|
||||
color: #c8c8c8;
|
||||
font-size: 12px;
|
||||
}
|
||||
QFrame.divider {
|
||||
background: #3a3a3a;
|
||||
min-height: 1px; max-height: 1px; border: none;
|
||||
}
|
||||
QLabel.h3 {
|
||||
color: #e6e6e6;
|
||||
font-weight: 600;
|
||||
margin-top: 6px;
|
||||
}
|
||||
QLabel.body {
|
||||
color: #dcdcdc;
|
||||
}
|
||||
/* Callouts */
|
||||
QFrame.warn {
|
||||
background: #3b2e1b;
|
||||
border: 1px solid #ffb74d;
|
||||
border-radius: 8px;
|
||||
}
|
||||
QLabel.warnTitle { color: #ffd561; font-weight: 700; }
|
||||
QLabel.warnText { color: #f0e0c0; }
|
||||
QFrame.tip {
|
||||
background: #1f3326;
|
||||
border: 1px solid #62d39b;
|
||||
border-radius: 8px;
|
||||
}
|
||||
QLabel.tipTitle { color: #a8f5c9; font-weight: 700; }
|
||||
QLabel.tipText { color: #d6ffe9; }
|
||||
QLabel.link { color: #6aa9ff; }
|
||||
""")
|
||||
|
||||
card_lay = QVBoxLayout(card)
|
||||
card_lay.setContentsMargins(18, 16, 18, 16)
|
||||
card_lay.setSpacing(12)
|
||||
|
||||
# Header
|
||||
title = QLabel("Help & User Guide")
|
||||
title.setProperty("class", "title")
|
||||
# header
|
||||
title = QLabel("Help & User Guide"); title.setObjectName("helpTitle")
|
||||
subtitle = QLabel("Follow these steps to get connected, monitor the station, and troubleshoot issues.")
|
||||
subtitle.setProperty("class", "subtitle")
|
||||
subtitle.setObjectName("helpSubtitle")
|
||||
|
||||
card_lay.addWidget(title)
|
||||
card_lay.addWidget(subtitle)
|
||||
|
||||
div1 = QFrame(); div1.setObjectName("divider"); div1.setFrameShape(QFrame.Shape.NoFrame); div1.setProperty("class", "divider")
|
||||
div1 = QFrame(); div1.setObjectName("helpDivider")
|
||||
card_lay.addWidget(div1)
|
||||
|
||||
# Quick Start
|
||||
qs_title = QLabel("Quick Start")
|
||||
qs_title.setProperty("class", "h3")
|
||||
qs_title = QLabel("Quick Start"); qs_title.setObjectName("sectionTitle")
|
||||
qs = QLabel(
|
||||
"<ul style='margin:0 0 0 16px'>"
|
||||
"<li><b>Configure</b>: Open <b>Config</b>, fill MQTT details, click <b>Connect</b>.</li>"
|
||||
|
|
@ -218,16 +170,14 @@ class MainWindow(QMainWindow):
|
|||
"</ul>"
|
||||
)
|
||||
qs.setOpenExternalLinks(True)
|
||||
qs.setProperty("class", "body")
|
||||
|
||||
qs.setObjectName("bodyText")
|
||||
card_lay.addWidget(qs_title)
|
||||
card_lay.addWidget(qs)
|
||||
|
||||
# Tips (green)
|
||||
tip_box = QFrame(); tip_box.setObjectName("tip"); tip_box.setProperty("class", "tip")
|
||||
# Tips
|
||||
tip_box = QFrame(); tip_box.setObjectName("tipBox")
|
||||
tip_lay = QVBoxLayout(tip_box); tip_lay.setContentsMargins(12, 10, 12, 10)
|
||||
tip_h = QLabel("💡 Tips")
|
||||
tip_h.setProperty("class", "tipTitle")
|
||||
tip_h = QLabel("💡 Tips"); tip_h.setObjectName("tipTitle")
|
||||
tip_b = QLabel(
|
||||
"<ul style='margin:0 0 0 16px'>"
|
||||
"<li>Use a stable, low-latency network for best live updates.</li>"
|
||||
|
|
@ -235,17 +185,16 @@ class MainWindow(QMainWindow):
|
|||
"<li>Use <b>Logs → Export</b> before clearing or reinstalling.</li>"
|
||||
"</ul>"
|
||||
)
|
||||
tip_b.setProperty("class", "tipText")
|
||||
tip_b.setOpenExternalLinks(True)
|
||||
tip_b.setObjectName("tipText")
|
||||
tip_lay.addWidget(tip_h)
|
||||
tip_lay.addWidget(tip_b)
|
||||
card_lay.addWidget(tip_box)
|
||||
|
||||
# Warnings (amber)
|
||||
warn_box = QFrame(); warn_box.setObjectName("warn"); warn_box.setProperty("class", "warn")
|
||||
# Warnings
|
||||
warn_box = QFrame(); warn_box.setObjectName("warnBox")
|
||||
warn_lay = QVBoxLayout(warn_box); warn_lay.setContentsMargins(12, 10, 12, 10)
|
||||
warn_h = QLabel("⚠️ Important Warnings")
|
||||
warn_h.setProperty("class", "warnTitle")
|
||||
warn_h = QLabel("⚠️ Important Warnings"); warn_h.setObjectName("warnTitle")
|
||||
warn_b = QLabel(
|
||||
"<ul style='margin:0 0 0 16px'>"
|
||||
"<li><b>Disconnected</b> state means no live data. Check server, network, and credentials.</li>"
|
||||
|
|
@ -253,14 +202,13 @@ class MainWindow(QMainWindow):
|
|||
"<li>Commands during disconnect may be lost. Reconnect before critical actions.</li>"
|
||||
"</ul>"
|
||||
)
|
||||
warn_b.setProperty("class", "warnText")
|
||||
warn_b.setObjectName("warnText")
|
||||
warn_lay.addWidget(warn_h)
|
||||
warn_lay.addWidget(warn_b)
|
||||
card_lay.addWidget(warn_box)
|
||||
|
||||
# Troubleshooting
|
||||
tr_title = QLabel("Troubleshooting")
|
||||
tr_title.setProperty("class", "h3")
|
||||
tr_title = QLabel("Troubleshooting"); tr_title.setObjectName("sectionTitle")
|
||||
tr = QLabel(
|
||||
"<ul style='margin:0 0 0 16px'>"
|
||||
"<li><b>Cannot connect</b>: Verify broker/port, username/password, and firewall.</li>"
|
||||
|
|
@ -269,175 +217,197 @@ class MainWindow(QMainWindow):
|
|||
"<li><b>Wrong station showing</b>: Confirm the <b>Device ID</b> matches the station you expect.</li>"
|
||||
"</ul>"
|
||||
)
|
||||
tr.setProperty("class", "body")
|
||||
tr.setObjectName("bodyText")
|
||||
card_lay.addWidget(tr_title)
|
||||
card_lay.addWidget(tr)
|
||||
|
||||
# Footer
|
||||
div2 = QFrame(); div2.setObjectName("divider"); div2.setProperty("class", "divider")
|
||||
# footer
|
||||
div2 = QFrame(); div2.setObjectName("helpDivider")
|
||||
card_lay.addWidget(div2)
|
||||
foot = QLabel("Need help? Email <a href='mailto:kirubakaran@vecmocon.com' class='link'>kirubakaran@vecmocon.com</a>")
|
||||
foot = QLabel("Need help? Email "
|
||||
"<a href='mailto:kirubakaran@vecmocon.com' style='color:#0d6efd; text-decoration:none'>"
|
||||
"kirubakaran@vecmocon.com</a>")
|
||||
foot.setOpenExternalLinks(True)
|
||||
foot.setProperty("class", "body")
|
||||
foot.setObjectName("bodyText")
|
||||
card_lay.addWidget(foot)
|
||||
|
||||
scroll_lay.addWidget(card)
|
||||
scroll_lay.addStretch(1)
|
||||
# assemble
|
||||
host_lay.addWidget(card)
|
||||
host_lay.addStretch(1)
|
||||
scroll.setWidget(host)
|
||||
root.addWidget(scroll)
|
||||
|
||||
def _about_stylesheet() -> str:
|
||||
return """
|
||||
/* Card */
|
||||
#aboutCard {
|
||||
background: #121417;
|
||||
border: 1px solid #2a2f36;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
/* Title + subtitle */
|
||||
#title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #e8edf2;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
#subtitle {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #9aa4b2;
|
||||
}
|
||||
|
||||
/* Divider */
|
||||
#divider {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #1b1f24, stop:0.5 #2a2f36, stop:1 #1b1f24);
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
border: none;
|
||||
margin: 6px 0 8px 0;
|
||||
}
|
||||
|
||||
/* Small label on the left column */
|
||||
#kvLabel {
|
||||
color: #aab4c0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Pill badge */
|
||||
#badge {
|
||||
color: #eaf3ff;
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #2563eb, stop:1 #7c3aed);
|
||||
border-radius: 999px;
|
||||
padding: 5px 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
QLabel { color: #d7dde6; }
|
||||
QLabel:hover { text-decoration: none; }
|
||||
QLabel[link='true'] { color: #6aa8ff; }
|
||||
QLabel[link='true']:hover { color: #8fc2ff; text-decoration: underline; }
|
||||
|
||||
/* Footer */
|
||||
#footer {
|
||||
color: #7e8895;
|
||||
font-size: 12px;
|
||||
}
|
||||
"""
|
||||
|
||||
def setup_about_ui(self):
|
||||
"""
|
||||
A clean, native-Qt About page:
|
||||
- Card-style container with rounded corners
|
||||
- Bold title + subtitle
|
||||
- Small badges for version/build
|
||||
- Left/right aligned key–value grid
|
||||
"""
|
||||
|
||||
# Clear existing layout if re-building
|
||||
def clear_layout(w: QWidget):
|
||||
lay = w.layout()
|
||||
if lay:
|
||||
while lay.count():
|
||||
item = lay.takeAt(0)
|
||||
if item.widget():
|
||||
item.widget().deleteLater()
|
||||
elif item.layout():
|
||||
while item.layout().count():
|
||||
sub = item.layout().takeAt(0)
|
||||
if sub.widget():
|
||||
sub.widget().deleteLater()
|
||||
item.layout().deleteLater()
|
||||
lay.deleteLater()
|
||||
|
||||
clear_layout(self.about_tab)
|
||||
|
||||
build_num = "4.0"
|
||||
|
||||
# ---- Main container ----
|
||||
root = QVBoxLayout(self.about_tab)
|
||||
root.setContentsMargins(16, 16, 16, 16)
|
||||
root.setSpacing(12)
|
||||
# get or create root layout
|
||||
root = self.about_tab.layout()
|
||||
if root is None:
|
||||
root = QVBoxLayout()
|
||||
root.setContentsMargins(24, 24, 24, 24)
|
||||
root.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter)
|
||||
self.about_tab.setLayout(root)
|
||||
else:
|
||||
# clear existing items
|
||||
while root.count():
|
||||
item = root.takeAt(0)
|
||||
w = item.widget()
|
||||
if w:
|
||||
w.setParent(None)
|
||||
w.deleteLater()
|
||||
|
||||
# --- card ---
|
||||
card = QFrame()
|
||||
card.setObjectName("aboutCard")
|
||||
card.setFrameShape(QFrame.Shape.NoFrame)
|
||||
card.setStyleSheet("""
|
||||
#aboutCard {
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 12px;
|
||||
}
|
||||
QLabel#title {
|
||||
color: #eaeaea;
|
||||
font-weight: 700;
|
||||
}
|
||||
QLabel#subtitle {
|
||||
color: #c7c7c7;
|
||||
}
|
||||
QLabel#label {
|
||||
color: #b6b6b6;
|
||||
font-weight: 600;
|
||||
}
|
||||
QLabel#value {
|
||||
color: #e6e6e6;
|
||||
}
|
||||
QLabel.badge {
|
||||
background: #343a40;
|
||||
border: 1px solid #454d55;
|
||||
border-radius: 999px;
|
||||
padding: 2px 10px;
|
||||
color: #e6e6e6;
|
||||
font-size: 11px;
|
||||
}
|
||||
QFrame#divider {
|
||||
background: #3a3a3a;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
border: none;
|
||||
}
|
||||
QLabel.link {
|
||||
color: #6aa9ff;
|
||||
}
|
||||
""")
|
||||
card_lay = QVBoxLayout(card)
|
||||
card_lay.setContentsMargins(18, 16, 18, 16)
|
||||
card_lay.setSpacing(10)
|
||||
card.setMinimumWidth(560)
|
||||
card.setMaximumWidth(760)
|
||||
card.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum)
|
||||
|
||||
# ---- Header ----
|
||||
shadow = QGraphicsDropShadowEffect(blurRadius=28, xOffset=0, yOffset=12)
|
||||
shadow.setColor(Qt.GlobalColor.black)
|
||||
card.setGraphicsEffect(shadow)
|
||||
|
||||
card_layout = QVBoxLayout(card)
|
||||
card_layout.setContentsMargins(28, 22, 28, 22)
|
||||
card_layout.setSpacing(14)
|
||||
|
||||
# --- header row (logo + titles + badge) ---
|
||||
header = QHBoxLayout()
|
||||
header.setSpacing(12)
|
||||
|
||||
# optional logo (put a 48px logo at ./logo/app.png if you have one)
|
||||
logo_label = QLabel()
|
||||
logo_path = "logo/v_logo.png"
|
||||
pix = QPixmap(logo_path)
|
||||
if not pix.isNull():
|
||||
logo_label.setPixmap(pix.scaled(40, 40, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation))
|
||||
logo_label.setFixedSize(44, 44)
|
||||
header.addWidget(logo_label, 0, Qt.AlignmentFlag.AlignTop)
|
||||
|
||||
title_box = QVBoxLayout()
|
||||
title = QLabel("About This Application")
|
||||
title.setObjectName("title")
|
||||
tfont = QFont()
|
||||
tfont.setPointSize(16)
|
||||
tfont.setBold(True)
|
||||
title.setFont(tfont)
|
||||
|
||||
subtitle = QLabel("Battery Swap Station Dashboard")
|
||||
subtitle.setObjectName("subtitle")
|
||||
title_box.addWidget(title)
|
||||
title_box.addWidget(subtitle)
|
||||
header.addLayout(title_box, 1)
|
||||
|
||||
header = QVBoxLayout()
|
||||
header.setSpacing(4)
|
||||
header.addWidget(title)
|
||||
header.addWidget(subtitle)
|
||||
badge = QLabel("Version 4.0")
|
||||
badge.setObjectName("badge")
|
||||
header.addWidget(badge, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
# badges row
|
||||
badges = QHBoxLayout()
|
||||
badges.setSpacing(8)
|
||||
ver = QLabel(f"Version: {build_num}")
|
||||
ver.setObjectName("")
|
||||
ver.setProperty("class", "badge")
|
||||
ver.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
ver.setMinimumHeight(20)
|
||||
ver.setStyleSheet("")
|
||||
card_layout.addLayout(header)
|
||||
|
||||
badges.addWidget(ver, 0, Qt.AlignmentFlag.AlignLeft)
|
||||
badges.addStretch(1)
|
||||
# --- divider ---
|
||||
divider = QFrame()
|
||||
divider.setObjectName("divider")
|
||||
card_layout.addWidget(divider)
|
||||
|
||||
card_lay.addLayout(header)
|
||||
card_lay.addLayout(badges)
|
||||
|
||||
# divider
|
||||
div = QFrame()
|
||||
div.setObjectName("divider")
|
||||
card_lay.addWidget(div)
|
||||
|
||||
# ---- Key–Value grid ----
|
||||
# --- key–value grid ---
|
||||
grid = QGridLayout()
|
||||
grid.setHorizontalSpacing(24)
|
||||
grid.setHorizontalSpacing(18)
|
||||
grid.setVerticalSpacing(10)
|
||||
|
||||
def add_row(r, key, val, is_link=False):
|
||||
l = QLabel(key)
|
||||
l.setObjectName("label")
|
||||
v = QLabel(val)
|
||||
v.setObjectName("value")
|
||||
def add_row(r: int, key: str, value: str, is_link: bool = False):
|
||||
k = QLabel(key)
|
||||
k.setObjectName("kvLabel")
|
||||
v = QLabel(value)
|
||||
v.setWordWrap(False) # instead of True
|
||||
|
||||
if is_link:
|
||||
v.setText(f'<a href="{val}">{val}</a>')
|
||||
v.setTextFormat(Qt.TextFormat.RichText)
|
||||
v.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction) # links + selection + keyboard nav
|
||||
v.setOpenExternalLinks(True)
|
||||
v.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
|
||||
v.setObjectName("") # style via link class
|
||||
v.setProperty("class", "link")
|
||||
grid.addWidget(l, r, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
grid.addWidget(v, r, 1, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
||||
v.setProperty("link", True)
|
||||
|
||||
add_row(0, "Company", "VECMOCON TECHNOLOGIES")
|
||||
else:
|
||||
v.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
|
||||
grid.addWidget(k, r, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop)
|
||||
grid.addWidget(v, r, 1, Qt.AlignmentFlag.AlignLeft)
|
||||
|
||||
add_row(0, "Company", "VECMOCON TECHNOLOGIES")
|
||||
add_row(1, "Developed by", "Kirubakaran S")
|
||||
add_row(2, "Support", "kirubakaran@vecmocon.com", is_link=True) # mailto auto-handled by client
|
||||
add_row(3, "Website", "https://www.vecmocon.com", is_link=True)
|
||||
add_row(2, "Support",
|
||||
"<a href='mailto:kirubakaran@vecmocon.com' style='color:#0d6efd; text-decoration:none'>kirubakaran@vecmocon.com</a>",
|
||||
is_link=True)
|
||||
|
||||
card_lay.addLayout(grid)
|
||||
add_row(3, "Website",
|
||||
"<a href='https://www.vecmocon.com' style='color:#0d6efd; text-decoration:none'>www.vecmocon.com</a>",
|
||||
is_link=True)
|
||||
|
||||
# footer
|
||||
footer = QLabel("© 2025 VECMOCON TECHNOLOGIES. All rights reserved. • Made with ♥ for reliability & clarity.")
|
||||
footer.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||
footer.setObjectName("subtitle") # subtle color
|
||||
card_lay.addSpacing(6)
|
||||
card_lay.addWidget(footer)
|
||||
card_layout.addLayout(grid)
|
||||
|
||||
# center the card horizontally
|
||||
root.addWidget(card)
|
||||
root.addStretch(1)
|
||||
# --- tiny space + footer ---
|
||||
spacer = QFrame(); spacer.setFixedHeight(4)
|
||||
card_layout.addWidget(spacer)
|
||||
|
||||
footer = QLabel("© 2025 VECMOCON TECHNOLOGIES. All rights reserved.")
|
||||
footer.setObjectName("footer")
|
||||
card_layout.addWidget(footer, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
root.addWidget(card, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
|
||||
def load_settings(self):
|
||||
|
|
@ -590,6 +560,8 @@ class MainWindow(QMainWindow):
|
|||
# 3. Immediately apply the new theme underneath the overlay
|
||||
self.is_dark_theme = not self.is_dark_theme
|
||||
self._apply_theme()
|
||||
self.setup_about_ui()
|
||||
self.setup_help_ui()
|
||||
|
||||
# 4. Set up the opacity effect and animation for the overlay
|
||||
opacity_effect = QGraphicsOpacityEffect(overlay)
|
||||
|
|
@ -609,6 +581,7 @@ class MainWindow(QMainWindow):
|
|||
self.animation.start(self.animation.DeletionPolicy.DeleteWhenStopped)
|
||||
|
||||
def create_status_bar(self):
|
||||
|
||||
status_bar_widget = QWidget()
|
||||
status_bar_widget.setStyleSheet(f"background-color: #2c3e50; padding: {int(6*self.scale_factor)}px;")
|
||||
status_bar_layout = QHBoxLayout(status_bar_widget)
|
||||
|
|
@ -634,6 +607,17 @@ class MainWindow(QMainWindow):
|
|||
right_layout.addStretch()
|
||||
self.connect_button = QPushButton("Connect")
|
||||
self.disconnect_button = QPushButton("Disconnect")
|
||||
button_font_size = max(10, int(12 * self.scale_factor))
|
||||
button_stylesheet = f"""
|
||||
QPushButton {{
|
||||
font-size: {button_font_size}px;
|
||||
font-weight: bold;
|
||||
padding: 4px 14px;
|
||||
background-color: #3498db;
|
||||
}}
|
||||
"""
|
||||
self.connect_button.setStyleSheet(button_stylesheet)
|
||||
self.disconnect_button.setStyleSheet(button_stylesheet)
|
||||
self.connect_button.setObjectName("ConnectButton")
|
||||
self.disconnect_button.setObjectName("DisconnectButton")
|
||||
self.disconnect_button.setEnabled(False)
|
||||
|
|
@ -781,14 +765,19 @@ class MainWindow(QMainWindow):
|
|||
int(8 * self.scale_factor), int(8 * self.scale_factor)
|
||||
)
|
||||
|
||||
# You correctly created the frame here
|
||||
self.top_bar_frame = QFrame()
|
||||
self.top_bar_frame.setObjectName("topBarFrame")
|
||||
|
||||
top_bar_layout = QHBoxLayout()
|
||||
top_bar_layout.addWidget(QLabel("LAST RECV TS:"))
|
||||
|
||||
ts_label = QLabel("LAST RECV TS:")
|
||||
ts_label.setObjectName("TimestampTitleLabel")
|
||||
top_bar_layout.addWidget(ts_label)
|
||||
|
||||
self.last_recv_ts_field = QLineEdit("No Data")
|
||||
self.last_recv_ts_field.setReadOnly(True)
|
||||
|
||||
self.last_recv_ts_field.setObjectName("TimestampDataField")
|
||||
top_bar_layout.addWidget(self.last_recv_ts_field)
|
||||
top_bar_layout.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum))
|
||||
|
||||
|
|
|
|||
869
ui/styles.py
869
ui/styles.py
|
|
@ -1,25 +1,451 @@
|
|||
# # --- Dynamic Theme Stylesheets ---
|
||||
|
||||
# def get_light_theme_styles(scale=1.0):
|
||||
# log_font_size = max(10, int(11 * scale))
|
||||
# button_font_size = max(7, int(10 * scale))
|
||||
|
||||
# return f"""
|
||||
# QMainWindow, QWidget {{
|
||||
# background-color: #f0f0f0;
|
||||
# color: #000;
|
||||
# }}
|
||||
|
||||
# /* --- ADDED THIS RULE --- */
|
||||
# #StatusBar {{
|
||||
# background-color: #34495e; /* A dark blue-grey for light theme */
|
||||
# padding: {int(6 * scale)}px;
|
||||
# }}
|
||||
|
||||
# #LogPanel {{
|
||||
# font-family: "Courier New", Consolas, monospace;
|
||||
# font-size: {log_font_size}pt;
|
||||
# background-color: #ffffff; /* White background for logs */
|
||||
# color: #2b2b2b;
|
||||
# border: 1px solid #c8c8c8;
|
||||
# }}
|
||||
# QGroupBox {{
|
||||
# font-family: Arial;
|
||||
# border: 1px solid #c8c8c8;
|
||||
# border-radius: {int(8 * scale)}px;
|
||||
# margin-top: {int(6 * scale)}px;
|
||||
# }}
|
||||
# QGroupBox::title {{
|
||||
# subcontrol-origin: margin;
|
||||
# subcontrol-position: top center;
|
||||
# padding: 0 {int(10 * scale)}px;
|
||||
# color: #000;
|
||||
# }}
|
||||
# QTabWidget::pane {{ border-top: 2px solid #c8c8c8; }}
|
||||
# QTabBar::tab {{
|
||||
# background: #e1e1e1; border: 1px solid #c8c8c8;
|
||||
# padding: {int(6 * scale)}px {int(15 * scale)}px;
|
||||
# border-top-left-radius: {int(4 * scale)}px; border-top-right-radius: {int(4 * scale)}px;
|
||||
# }}
|
||||
# QTabBar::tab:selected {{ background: #f0f0f0; border-bottom-color: #f0f0f0; }}
|
||||
# QFormLayout::label {{ color: #000; padding-top: {int(3 * scale)}px; }}
|
||||
# QLineEdit, QPlainTextEdit, QComboBox {{
|
||||
# background-color: #fff; border: 1px solid #c8c8c8;
|
||||
# border-radius: {int(4 * scale)}px; padding: {int(4 * scale)}px;
|
||||
# font-size: {max(7, int(9 * scale))}pt;
|
||||
# color: #000;
|
||||
# }}
|
||||
# QLineEdit:read-only {{ background-color: #e9e9e9; }}
|
||||
# QPushButton {{
|
||||
# background-color: #e1e1e1; border: 1px solid #c8c8c8;
|
||||
# padding: {int(5 * scale)}px {int(10 * scale)}px;
|
||||
# border-radius: {int(4 * scale)}px;
|
||||
# color: #000;
|
||||
# }}
|
||||
# QPushButton:hover {{ background-color: #dcdcdc; }}
|
||||
# QPushButton:pressed {{ background-color: #c8c8c8; }}
|
||||
# QPushButton:disabled {{ background-color: #d3d3d3; color: #a0a0a0; }}
|
||||
|
||||
# #RefreshButton, #ResetButton {{
|
||||
# padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
# font-size: {button_font_size * 1.3}pt;
|
||||
# font-weight: bold;
|
||||
# color: white;
|
||||
# border-radius: {int(4*scale)}px;
|
||||
# }}
|
||||
|
||||
# #RefreshButton {{
|
||||
# background-color: #2e7d32; /* A slightly darker green */
|
||||
# }}
|
||||
# #ResetButton {{
|
||||
# background-color: #c62828; /* A slightly darker red */
|
||||
# }}
|
||||
|
||||
# /* --- UPDATED BUTTON STYLES FOR LIGHT THEME --- */
|
||||
# #ConnectButton, #DisconnectButton, #StartSwapButton, #AbortSwapButton {{
|
||||
# padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
# font-size: {button_font_size}pt;
|
||||
# font-weight: bold;
|
||||
# border-radius: {int(4 * scale)}px;
|
||||
# color: white;
|
||||
# border: none;
|
||||
# }}
|
||||
|
||||
# /* Positive Actions (Green) */
|
||||
# #ConnectButton, #StartSwapButton {{
|
||||
# background-color: #28a745;
|
||||
# }}
|
||||
# #ConnectButton:hover, #StartSwapButton:hover {{
|
||||
# background-color: #218838;
|
||||
# }}
|
||||
# /* Negative Actions (Red) */
|
||||
# #DisconnectButton, #AbortSwapButton {{
|
||||
# background-color: #dc3545;
|
||||
# }}
|
||||
# #DisconnectButton:hover, #AbortSwapButton:hover {{
|
||||
# background-color: #c82333;
|
||||
# }}
|
||||
# /* Disabled States */
|
||||
# #ConnectButton:disabled, #DisconnectButton:disabled {{
|
||||
# background-color: #b0bec5;
|
||||
# color: #78909c;
|
||||
# }}
|
||||
# /* Unique Buttons */
|
||||
# #SendAudioButton {{
|
||||
# background-color: #007bff;
|
||||
# color: white;
|
||||
# border: none;
|
||||
# font-size: {max(10, int(14 * scale))}px;
|
||||
# }}
|
||||
# #SendAudioButton:hover {{
|
||||
# background-color: #0069d9;
|
||||
# }}
|
||||
|
||||
# #ChamberOpenDoorButton, #ChamberChgOnButton, #ChamberChgOffButton {{
|
||||
# padding: {int(8 * scale)}px;
|
||||
# font-size: {button_font_size}pt;
|
||||
# font-weight: bold;
|
||||
# border-radius: {int(4*scale)}px;
|
||||
# }}
|
||||
|
||||
# #ChamberOpenDoorButton:hover {{ background-color: #607d8b; }}
|
||||
# #ChamberChgOnButton:hover {{ background-color: #52be80; }}
|
||||
# #ChamberChgOffButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
# /* --- STATUS & ALARM LABELS --- */
|
||||
# QLabel[status="present"] {{ background-color: #2ecc71; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
# QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
# QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
# QLabel[alarm="inactive"] {{ background-color: transparent; color: black; }}
|
||||
# QGroupBox#ChamberWidget {{ border: 2px solid #007bff; }}
|
||||
|
||||
# /* --- ADDED TIMESTAMP STYLES --- */
|
||||
# QLabel#TimestampTitleLabel {{
|
||||
# font-size: {max(9, int(11 * scale))}pt;
|
||||
# font-weight: bold;
|
||||
# color: #333;
|
||||
# }}
|
||||
# QLineEdit#TimestampDataField {{
|
||||
# font-size: {max(11, int(13 * scale))}pt;
|
||||
# font-weight: bold;
|
||||
# color: #000;
|
||||
# }}
|
||||
|
||||
# QGroupBox#ChamberWidget QFormLayout QLabel {{
|
||||
# font-size: {max(10, int(12 * scale))}px;
|
||||
# color: #555555;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#BatIdField {{
|
||||
# font-size: {max(14, int(16 * scale))}px;
|
||||
# font-weight: bold;
|
||||
# color: #000000;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#DataField {{
|
||||
# font-size: {max(13, int(14 * scale))}px;
|
||||
# color: #222222;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#DoorStatusField {{
|
||||
# font-size: {max(12, int(14 * scale))}px;
|
||||
# font-weight: bold;
|
||||
# color: #222222;
|
||||
# }}
|
||||
|
||||
# #aboutCard {{
|
||||
# background-color: #ffffff; /* White background */
|
||||
# border: 1px solid #dee2e6; /* Light grey border */
|
||||
# border-radius: 12px;
|
||||
# }}
|
||||
# #aboutCard QLabel#title {{
|
||||
# color: #212529; /* Dark text for title */
|
||||
# font-size: 18pt;
|
||||
# font-weight: bold;
|
||||
# }}
|
||||
# #aboutCard QLabel#subtitle {{
|
||||
# color: #6c757d; /* Grey for subtitle */
|
||||
# }}
|
||||
# #aboutCard QLabel#label {{
|
||||
# color: #495057; /* Dark grey for labels */
|
||||
# font-weight: bold;
|
||||
# }}
|
||||
# #aboutCard QLabel {{ /* General text color inside the card */
|
||||
# color: #212529;
|
||||
# }}
|
||||
# #aboutCard QLabel.badge {{
|
||||
# background-color: #e9ecef; /* Light grey for badge */
|
||||
# border-radius: 8px;
|
||||
# padding: 3px 10px;
|
||||
# font-size: 9pt;
|
||||
# }}
|
||||
# #aboutCard QFrame#divider {{
|
||||
# background-color: #dee2e6; /* Light grey for divider line */
|
||||
# max-height: 1px;
|
||||
# border: none;
|
||||
# }}
|
||||
# #aboutCard a {{
|
||||
# color: #007bff; /* Standard blue for links */
|
||||
# text-decoration: none;
|
||||
# }}
|
||||
# """
|
||||
|
||||
# def get_dark_theme_styles(scale=1.0):
|
||||
|
||||
# log_font_size = max(10, int(11 * scale))
|
||||
# button_font_size = max(7, int(10 * scale))
|
||||
|
||||
# return f"""
|
||||
# QMainWindow, QWidget {{ background-color: #2b2b2b; color: #f0f0f0; }}
|
||||
# #LogPanel {{
|
||||
# font-family: "Courier New", Consolas, monospace;
|
||||
# font-size: {log_font_size}pt;
|
||||
# background-color: #212121;
|
||||
# color: #eceff1;
|
||||
# border: 1px solid #455a64;
|
||||
# }}
|
||||
# QGroupBox {{
|
||||
# font-family: Arial; border: 1px solid #4a4a4a;
|
||||
# border-radius: {int(8 * scale)}px; margin-top: {int(6 * scale)}px;
|
||||
# }}
|
||||
# QGroupBox::title {{ subcontrol-origin: margin; subcontrol-position: top center; padding: 0 {int(10 * scale)}px; color: #f0f0f0; }}
|
||||
# QTabWidget::pane {{ border-top: 2px solid #4a4a4a; }}
|
||||
# QTabBar::tab {{
|
||||
# background: #3c3c3c; border: 1px solid #4a4a4a; color: #f0f0f0;
|
||||
# padding: {int(6 * scale)}px {int(15 * scale)}px;
|
||||
# border-top-left-radius: {int(4 * scale)}px; border-top-right-radius: {int(4 * scale)}px;
|
||||
# }}
|
||||
# QTabBar::tab:selected {{ background: #2b2b2b; border-bottom-color: #2b2b2b; }}
|
||||
# QFormLayout::label {{ color: #f0f0f0; padding-top: {int(3 * scale)}px; }}
|
||||
# QLineEdit, QPlainTextEdit, QComboBox {{
|
||||
# background-color: #3c3c3c; border: 1px solid #4a4a4a;
|
||||
# border-radius: {int(4 * scale)}px; padding: {int(4 * scale)}px; color: #f0f0f0;
|
||||
# font-size: {max(7, int(9 * scale))}pt;
|
||||
# }}
|
||||
# QLineEdit:read-only {{ background-color: #333333; }}
|
||||
# QPushButton {{
|
||||
# background-color: #555555; border: 1px solid #4a4a4a;
|
||||
# padding: {int(5 * scale)}px {int(10 * scale)}px;
|
||||
# border-radius: {int(4 * scale)}px; color: #f0f0f0;
|
||||
# }}
|
||||
# QPushButton:hover {{ background-color: #6a6a6a; }}
|
||||
# QPushButton:pressed {{ background-color: #4a4a4a; }}
|
||||
# QPushButton:disabled {{ background-color: #404040; color: #888888; }}
|
||||
# #RefreshButton, #ResetButton {{
|
||||
# padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
# font-size: {button_font_size * 1.3}pt;
|
||||
# font-weight: bold;
|
||||
# border-radius: {int(4*scale)}px;
|
||||
# }}
|
||||
# #RefreshButton {{
|
||||
# background-color: #2e7d32; /* A slightly darker green */
|
||||
# }}
|
||||
# #ResetButton {{
|
||||
# background-color: #c62828; /* A slightly darker red */
|
||||
# }}
|
||||
# #ChamberOpenDoorButton, #ChamberChgOnButton, #ChamberChgOffButton {{
|
||||
# padding: {int(8 * scale)}px;
|
||||
# font-size: {button_font_size}pt;
|
||||
# font-weight: bold;
|
||||
# border-radius: {int(4*scale)}px;
|
||||
# }}
|
||||
|
||||
# #ChamberOpenDoorButton {{ background-color: #3C3C3C; }}
|
||||
# #ChamberChgOnButton {{ background-color: #3C3C3C; }}
|
||||
# #ChamberChgOffButton {{ background-color: #3C3C3C; }}
|
||||
|
||||
# #ChamberOpenDoorButton:hover {{ background-color: #607d8b; }}
|
||||
# #ChamberChgOnButton:hover {{ background-color: #52be80; }}
|
||||
# #ChamberChgOffButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
# #ConnectButton, #DisconnectButton {{
|
||||
# padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
# font-size: {button_font_size}pt;
|
||||
# font-weight: bold;
|
||||
# border-radius: {int(4*scale)}px;
|
||||
# color: white;
|
||||
# }}
|
||||
|
||||
# #ConnectButton {{ background-color: #27ae60; }} /* Green */
|
||||
# #DisconnectButton {{ background-color: #c0392b; }} /* Red */
|
||||
|
||||
# #ConnectButton:hover {{ background-color: #52be80; }}
|
||||
# #DisconnectButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
# #ConnectButton:pressed {{ background-color: #52be80; }}
|
||||
# #DisconnectButton:pressed {{ background-color: #cd6155; }}
|
||||
|
||||
# #ConnectButton:disabled, #DisconnectButton:disabled {{
|
||||
# background-color: #546e7a;
|
||||
# color: #90a4ae;
|
||||
# }}
|
||||
|
||||
# #RefreshButton, #StartSwapButton {{ background-color: #27ae60; color: white; border: none; }}
|
||||
# #RefreshButton:hover, #StartSwapButton:hover {{ background-color: #52be80; }}
|
||||
# #ResetButton, #AbortSwapButton {{ background-color: #c0392b; color: white; border: none; }}
|
||||
# #ResetButton:hover, #AbortSwapButton:hover {{ background-color: #cd6155; }}
|
||||
# #SendAudioButton {{ background-color: #3498db; color: white; border: none; font-size: {max(10, int(14 * scale))}px; }}
|
||||
# #SendAudioButton:hover {{ background-color: #5dade2; }}
|
||||
# QLabel[status="present"] {{ background-color: #2ecc71; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
# QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
# QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
# QLabel[alarm="inactive"] {{ background-color: transparent; color: #f0f0f0; }}
|
||||
# QGroupBox#ChamberWidget {{ border: 2px solid #3498db; }}
|
||||
|
||||
# /* Style for the timestamp TITLE label */
|
||||
# QLabel#TimestampTitleLabel {{
|
||||
# font-size: {max(9, int(11 * scale))}pt; /* Normal font size */
|
||||
# font-weight: bold;
|
||||
# }}
|
||||
|
||||
# /* Style for the timestamp DATA field */
|
||||
# QLineEdit#TimestampDataField {{
|
||||
# font-size: {max(11, int(13 * scale))}pt; /* Larger font */
|
||||
# font-weight: bold;
|
||||
# color: #f0f0f0;
|
||||
# }}
|
||||
|
||||
# QGroupBox#ChamberWidget QFormLayout QLabel {{
|
||||
# font-size: {max(10, int(12 * scale))}px;
|
||||
# color: #AAAAAA;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#BatIdField {{
|
||||
# font-size: {max(14, int(16 * scale))}px;
|
||||
# font-weight: bold;
|
||||
# color: #FFFFFF;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#DataField {{
|
||||
# font-size: {max(13, int(14 * scale))}px;
|
||||
# color: #E0E0E0;
|
||||
# }}
|
||||
# QGroupBox#ChamberWidget QLineEdit#DoorStatusField {{
|
||||
# font-size: {max(12, int(14 * scale))}px;
|
||||
# font-weight: bold;
|
||||
# color: #E0E0E0;
|
||||
# }}
|
||||
|
||||
# QFrame#aboutCard {{
|
||||
# background: #2a2a2a;
|
||||
# border: 1px solid #3a3a3a;
|
||||
# border-radius: 12px;
|
||||
# }}
|
||||
# QFrame#aboutCard QLabel#title {{
|
||||
# color: #eaeaea;
|
||||
# font-size: 16pt;
|
||||
# font-weight: bold;
|
||||
# }}
|
||||
# QFrame#aboutCard QLabel#subtitle {{
|
||||
# color: #c7c7c7;
|
||||
# }}
|
||||
# QFrame#aboutCard QLabel#label {{
|
||||
# color: #b6b6b6;
|
||||
# font-weight: 600;
|
||||
# }}
|
||||
# QFrame#aboutCard QLabel#value {{
|
||||
# color: #e6e6e6;
|
||||
# }}
|
||||
# QFrame#aboutCard QLabel.badge {{
|
||||
# background: #343a40;
|
||||
# border: 1px solid #454d55;
|
||||
# border-radius: 8px;
|
||||
# padding: 2px 10px;
|
||||
# color: #e6e6e6;
|
||||
# font-size: 11px;
|
||||
# }}
|
||||
# QFrame#aboutCard QFrame#divider {{
|
||||
# background: #3a3a3a;
|
||||
# min-height: 1px; max-height: 1px; border: none;
|
||||
# }}
|
||||
# QFrame#aboutCard a {{
|
||||
# color: #6aa9ff;
|
||||
# text-decoration: none;
|
||||
# }}
|
||||
|
||||
# #aboutCard {{
|
||||
# background-color: #3c3c3c;
|
||||
# border: 1px solid #4a4a4a;
|
||||
# border-radius: 12px;
|
||||
# }}
|
||||
# #aboutCard QLabel#title {{ color: #eaeaea; font-size: 18pt; font-weight: bold; }}
|
||||
# #aboutCard QLabel#subtitle {{ color: #a0a0a0; }}
|
||||
# #aboutCard QLabel#label {{ color: #b0b0b0; font-weight: bold; }}
|
||||
# #aboutCard QLabel.badge {{
|
||||
# background-color: #555555; border-radius: 8px;
|
||||
# padding: 3px 10px; font-size: 9pt;
|
||||
# }}
|
||||
# #aboutCard QFrame#divider {{ background-color: #4a4a4a; max-height: 1px; border: none; }}
|
||||
# #aboutCard a {{ color: #6aa9ff; text-decoration: none; }}
|
||||
|
||||
# """
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# --- Dynamic Theme Stylesheets ---
|
||||
|
||||
def get_light_theme_styles(scale=1.0):
|
||||
|
||||
log_font_size = max(10, int(11 * scale))
|
||||
button_font_size = max(7, int(10 * scale))
|
||||
big_button_font = int(button_font_size * 13 // 10) # 1.3x as int
|
||||
|
||||
return f"""
|
||||
QMainWindow, QWidget {{
|
||||
background-color: #f0f0f0;
|
||||
color: #000;
|
||||
}}
|
||||
|
||||
/* Status Bar */
|
||||
#StatusBar {{
|
||||
background-color: #34495e;
|
||||
padding: {int(6 * scale)}px;
|
||||
}}
|
||||
|
||||
/* Logs */
|
||||
#LogPanel {{
|
||||
font-family: "Courier New", Consolas, monospace;
|
||||
font-size: {log_font_size}pt;
|
||||
background-color: #212121;
|
||||
color: #eceff1;
|
||||
border: 1px solid #455a64;
|
||||
background-color: #ffffff;
|
||||
color: #2b2b2b;
|
||||
border: 1px solid #c8c8c8;
|
||||
}}
|
||||
|
||||
/* Containers */
|
||||
QGroupBox {{
|
||||
font-family: Arial;
|
||||
border: 1px solid #4a4a4a;
|
||||
border: 1px solid #c8c8c8;
|
||||
border-radius: {int(8 * scale)}px;
|
||||
margin-top: {int(6 * scale)}px;
|
||||
}}
|
||||
|
|
@ -29,6 +455,8 @@ def get_light_theme_styles(scale=1.0):
|
|||
padding: 0 {int(10 * scale)}px;
|
||||
color: #000;
|
||||
}}
|
||||
|
||||
/* Tabs */
|
||||
QTabWidget::pane {{ border-top: 2px solid #c8c8c8; }}
|
||||
QTabBar::tab {{
|
||||
background: #e1e1e1; border: 1px solid #c8c8c8;
|
||||
|
|
@ -36,91 +464,212 @@ def get_light_theme_styles(scale=1.0):
|
|||
border-top-left-radius: {int(4 * scale)}px; border-top-right-radius: {int(4 * scale)}px;
|
||||
}}
|
||||
QTabBar::tab:selected {{ background: #f0f0f0; border-bottom-color: #f0f0f0; }}
|
||||
|
||||
/* Forms */
|
||||
QFormLayout::label {{ color: #000; padding-top: {int(3 * scale)}px; }}
|
||||
QLineEdit, QPlainTextEdit, QComboBox {{
|
||||
background-color: #fff; border: 1px solid #c8c8c8;
|
||||
border-radius: {int(4 * scale)}px; padding: {int(4 * scale)}px;
|
||||
font-size: {max(7, int(9 * scale))}pt;
|
||||
color: #000;
|
||||
}}
|
||||
QLineEdit:read-only {{ background-color: #e9e9e9; }}
|
||||
|
||||
/* Buttons (generic) */
|
||||
QPushButton {{
|
||||
background-color: #e1e1e1; border: 1px solid #c8c8c8;
|
||||
padding: {int(5 * scale)}px {int(10 * scale)}px;
|
||||
border-radius: {int(4 * scale)}px;
|
||||
color: #000;
|
||||
}}
|
||||
QPushButton:hover {{ background-color: #dcdcdc; }}
|
||||
QPushButton:pressed {{ background-color: #c8c8c8; }}
|
||||
#RefreshButton, #ResetButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size * 1.3}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#RefreshButton {{
|
||||
background-color: #2e7d32; /* A slightly darker green */
|
||||
}}
|
||||
#ResetButton {{
|
||||
background-color: #c62828; /* A slightly darker red */
|
||||
}}
|
||||
#ChamberOpenDoorButton, #ChamberChgOnButton, #ChamberChgOffButton {{
|
||||
padding: {int(8 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
|
||||
#ChamberOpenDoorButton {{ background-color: #E1E1E1; }}
|
||||
#ChamberChgOnButton {{ background-color: #E1E1E1; }}
|
||||
#ChamberChgOffButton {{ background-color: #E1E1E1; }}
|
||||
|
||||
#ChamberOpenDoorButton:hover {{ background-color: #3498DB; }}
|
||||
#ChamberChgOnButton:hover {{ background-color: #229954; }}
|
||||
#ChamberChgOffButton:hover {{ background-color: #c0392b; }}
|
||||
|
||||
QPushButton:disabled {{ background-color: #d3d3d3; color: #a0a0a0; }}
|
||||
|
||||
#ConnectButton, #DisconnectButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4 * scale)}px;
|
||||
color: white;
|
||||
|
||||
/* Primary/Destructive (larger) */
|
||||
#RefreshButton, #ResetButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {big_button_font}pt;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#RefreshButton {{ background-color: #2e7d32; }}
|
||||
#ResetButton {{ background-color: #c62828; }}
|
||||
|
||||
#ConnectButton {{ background-color: #27ae60; }} /* Green */
|
||||
#DisconnectButton {{ background-color: #c0392b; }} /* Red */
|
||||
|
||||
#ConnectButton:hover {{ background-color: #52be80; }}
|
||||
#DisconnectButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
#ConnectButton:pressed {{ background-color: #52be80; }}
|
||||
#DisconnectButton:pressed {{ background-color: #cd6155; }}
|
||||
|
||||
/* Action buttons */
|
||||
#ConnectButton, #DisconnectButton, #StartSwapButton, #AbortSwapButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4 * scale)}px;
|
||||
color: white;
|
||||
border: none;
|
||||
}}
|
||||
#ConnectButton, #StartSwapButton {{ background-color: #28a745; }}
|
||||
#ConnectButton:hover, #StartSwapButton:hover {{ background-color: #218838; }}
|
||||
#DisconnectButton, #AbortSwapButton {{ background-color: #dc3545; }}
|
||||
#DisconnectButton:hover, #AbortSwapButton:hover {{ background-color: #c82333; }}
|
||||
#ConnectButton:disabled, #DisconnectButton:disabled {{
|
||||
background-color: #546e7a;
|
||||
color: #90a4ae;
|
||||
background-color: #b0bec5; color: #78909c;
|
||||
}}
|
||||
|
||||
#RefreshButton, #StartSwapButton {{ background-color: #27ae60; color: white; border: none; }}
|
||||
#RefreshButton:hover, #StartSwapButton:hover {{ background-color: #229954; }}
|
||||
#ResetButton, #AbortSwapButton {{ background-color: #c0392b; color: white; border: none; }}
|
||||
#ResetButton:hover, #AbortSwapButton:hover {{ background-color: #c0392b; }}
|
||||
#SendAudioButton {{ background-color: #3498db; color: white; border: none; font-size: {max(10, int(14 * scale))}px; }}
|
||||
#SendAudioButton:hover {{ background-color: #2980b9; }}
|
||||
QLabel[status="present"] {{ background-color: #2ecc71; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
/* Unique */
|
||||
#SendAudioButton {{
|
||||
background-color: #007bff; color: white; border: none;
|
||||
font-size: {max(10, int(14 * scale))}px;
|
||||
}}
|
||||
#SendAudioButton:hover {{ background-color: #0069d9; }}
|
||||
|
||||
#ChamberOpenDoorButton, #ChamberChgOnButton, #ChamberChgOffButton {{
|
||||
padding: {int(8 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#ChamberOpenDoorButton:hover {{ background-color: #607d8b; }}
|
||||
#ChamberChgOnButton:hover {{ background-color: #52be80; }}
|
||||
#ChamberChgOffButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
/* Status & alarms */
|
||||
QLabel[status="present"] {{ background-color: #2ecc71; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
QLabel[alarm="inactive"] {{ background-color: transparent; color: black; }}
|
||||
QGroupBox#ChamberWidget {{ border: 2px solid #3498db; }}
|
||||
QGroupBox#ChamberWidget {{ border: 2px solid #007bff; }}
|
||||
|
||||
/* Timestamp */
|
||||
QLabel#TimestampTitleLabel {{
|
||||
font-size: {max(9, int(11 * scale))}pt; font-weight: bold; color: #333;
|
||||
}}
|
||||
QLineEdit#TimestampDataField {{
|
||||
font-size: {max(11, int(13 * scale))}pt; font-weight: bold; color: #000;
|
||||
}}
|
||||
|
||||
/* ---------- ABOUT CARD (LIGHT) ---------- */
|
||||
#aboutCard {{
|
||||
background: #ffffff;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 12px;
|
||||
}}
|
||||
#aboutCard #title {{
|
||||
color: #212529;
|
||||
font-size: {max(16, int(18 * scale))}pt;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2px;
|
||||
}}
|
||||
#aboutCard #subtitle {{
|
||||
color: #6c757d;
|
||||
font-size: {max(9, int(11 * scale))}pt;
|
||||
font-weight: 500;
|
||||
}}
|
||||
#aboutCard #kvLabel {{
|
||||
color: #495057;
|
||||
font-weight: 600;
|
||||
}}
|
||||
#aboutCard #badge {{
|
||||
color: #0b1220;
|
||||
background: #e9ecef;
|
||||
border-radius: 999px;
|
||||
padding: {int(5*scale)}px {int(12*scale)}px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.3px;
|
||||
font-size: {max(8, int(10*scale))}pt;
|
||||
}}
|
||||
#aboutCard #divider {{
|
||||
background: #dee2e6;
|
||||
min-height: 1px; max-height: 1px; border: none;
|
||||
margin: {int(6*scale)}px 0 {int(8*scale)}px 0;
|
||||
}}
|
||||
#aboutCard #footer {{
|
||||
color: #7a8794;
|
||||
font-size: {max(8, int(10*scale))}pt;
|
||||
}}
|
||||
#aboutCard a {{
|
||||
color: #007bff; text-decoration: none;
|
||||
}}
|
||||
#aboutCard a:hover {{
|
||||
text-decoration: underline;
|
||||
}}
|
||||
|
||||
#aboutCard [link="true"] {{
|
||||
color: #0d6efd; /* Bootstrap dark blue */
|
||||
text-decoration: none;
|
||||
}}
|
||||
|
||||
#aboutCard [link="true"]:hover {{
|
||||
color: #0a58ca; /* darker blue on hover */
|
||||
text-decoration: underline;
|
||||
}}
|
||||
|
||||
/* ---------- HELP CARD (LIGHT) ---------- */
|
||||
#helpCard {{
|
||||
background: #ffffff;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 12px;
|
||||
}}
|
||||
|
||||
#helpTitle {{
|
||||
color: #212529;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}}
|
||||
|
||||
#helpSubtitle {{
|
||||
color: #495057;
|
||||
font-size: 12px;
|
||||
}}
|
||||
|
||||
#helpDivider {{
|
||||
background: #dee2e6;
|
||||
min-height: 1px; max-height: 1px; border: none;
|
||||
}}
|
||||
|
||||
#sectionTitle {{
|
||||
color: #212529;
|
||||
font-weight: 600;
|
||||
margin-top: 6px;
|
||||
}}
|
||||
|
||||
#bodyText {{
|
||||
color: #343a40;
|
||||
}}
|
||||
|
||||
/* Callouts (light theme) */
|
||||
#tipBox {{
|
||||
background: #e6ffed;
|
||||
border: 1px solid #28a745;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
#tipTitle {{ color: #155724; font-weight: 700; }}
|
||||
#tipText {{ color: #155724; }}
|
||||
|
||||
#warnBox {{
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffb74d;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
#warnTitle {{ color: #856404; font-weight: 700; }}
|
||||
#warnText {{ color: #856404; }}
|
||||
|
||||
#link {{
|
||||
color: #0827F5; /* Current */
|
||||
text-decoration: none;
|
||||
}}
|
||||
#link:hover {{
|
||||
color: #00008b; /* Hover color */
|
||||
text-decoration: underline;
|
||||
}}
|
||||
|
||||
"""
|
||||
|
||||
def get_dark_theme_styles(scale=1.0):
|
||||
|
||||
log_font_size = max(10, int(11 * scale))
|
||||
button_font_size = max(7, int(10 * scale))
|
||||
|
||||
return f"""
|
||||
QMainWindow, QWidget {{ background-color: #2b2b2b; color: #f0f0f0; }}
|
||||
|
||||
#LogPanel {{
|
||||
font-family: "Courier New", Consolas, monospace;
|
||||
font-size: {log_font_size}pt;
|
||||
|
|
@ -128,11 +677,13 @@ def get_dark_theme_styles(scale=1.0):
|
|||
color: #eceff1;
|
||||
border: 1px solid #455a64;
|
||||
}}
|
||||
|
||||
QGroupBox {{
|
||||
font-family: Arial; border: 1px solid #4a4a4a;
|
||||
border-radius: {int(8 * scale)}px; margin-top: {int(6 * scale)}px;
|
||||
}}
|
||||
QGroupBox::title {{ subcontrol-origin: margin; subcontrol-position: top center; padding: 0 {int(10 * scale)}px; color: #f0f0f0; }}
|
||||
|
||||
QTabWidget::pane {{ border-top: 2px solid #4a4a4a; }}
|
||||
QTabBar::tab {{
|
||||
background: #3c3c3c; border: 1px solid #4a4a4a; color: #f0f0f0;
|
||||
|
|
@ -140,6 +691,7 @@ def get_dark_theme_styles(scale=1.0):
|
|||
border-top-left-radius: {int(4 * scale)}px; border-top-right-radius: {int(4 * scale)}px;
|
||||
}}
|
||||
QTabBar::tab:selected {{ background: #2b2b2b; border-bottom-color: #2b2b2b; }}
|
||||
|
||||
QFormLayout::label {{ color: #f0f0f0; padding-top: {int(3 * scale)}px; }}
|
||||
QLineEdit, QPlainTextEdit, QComboBox {{
|
||||
background-color: #3c3c3c; border: 1px solid #4a4a4a;
|
||||
|
|
@ -147,6 +699,7 @@ def get_dark_theme_styles(scale=1.0):
|
|||
font-size: {max(7, int(9 * scale))}pt;
|
||||
}}
|
||||
QLineEdit:read-only {{ background-color: #333333; }}
|
||||
|
||||
QPushButton {{
|
||||
background-color: #555555; border: 1px solid #4a4a4a;
|
||||
padding: {int(5 * scale)}px {int(10 * scale)}px;
|
||||
|
|
@ -155,53 +708,44 @@ def get_dark_theme_styles(scale=1.0):
|
|||
QPushButton:hover {{ background-color: #6a6a6a; }}
|
||||
QPushButton:pressed {{ background-color: #4a4a4a; }}
|
||||
QPushButton:disabled {{ background-color: #404040; color: #888888; }}
|
||||
|
||||
#RefreshButton, #ResetButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size * 1.3}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#RefreshButton {{
|
||||
background-color: #2e7d32; /* A slightly darker green */
|
||||
}}
|
||||
#ResetButton {{
|
||||
background-color: #c62828; /* A slightly darker red */
|
||||
}}
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {int(button_font_size * 1.3)}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#RefreshButton {{ background-color: #2e7d32; }}
|
||||
#ResetButton {{ background-color: #c62828; }}
|
||||
|
||||
#ChamberOpenDoorButton, #ChamberChgOnButton, #ChamberChgOffButton {{
|
||||
padding: {int(8 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
|
||||
#ChamberOpenDoorButton {{ background-color: #3C3C3C; }}
|
||||
#ChamberChgOnButton {{ background-color: #3C3C3C; }}
|
||||
#ChamberChgOffButton {{ background-color: #3C3C3C; }}
|
||||
|
||||
#ChamberOpenDoorButton:hover {{ background-color: #607d8b; }}
|
||||
#ChamberChgOnButton:hover {{ background-color: #52be80; }}
|
||||
#ChamberChgOffButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
#ConnectButton, #DisconnectButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
color: white;
|
||||
}}
|
||||
|
||||
#ConnectButton {{ background-color: #27ae60; }} /* Green */
|
||||
#DisconnectButton {{ background-color: #c0392b; }} /* Red */
|
||||
padding: {int(8 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
}}
|
||||
#ChamberOpenDoorButton {{ background-color: #3C3C3C; }}
|
||||
#ChamberChgOnButton {{ background-color: #3C3C3C; }}
|
||||
#ChamberChgOffButton {{ background-color: #3C3C3C; }}
|
||||
#ChamberOpenDoorButton:hover {{ background-color: #607d8b; }}
|
||||
#ChamberChgOnButton:hover {{ background-color: #52be80; }}
|
||||
#ChamberChgOffButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
#ConnectButton, #DisconnectButton {{
|
||||
padding: {int(6 * scale)}px {int(16 * scale)}px;
|
||||
font-size: {button_font_size}pt;
|
||||
font-weight: bold;
|
||||
border-radius: {int(4*scale)}px;
|
||||
color: white;
|
||||
}}
|
||||
#ConnectButton {{ background-color: #27ae60; }}
|
||||
#DisconnectButton {{ background-color: #c0392b; }}
|
||||
#ConnectButton:hover {{ background-color: #52be80; }}
|
||||
#DisconnectButton:hover {{ background-color: #cd6155; }}
|
||||
|
||||
#ConnectButton:pressed {{ background-color: #52be80; }}
|
||||
#DisconnectButton:pressed {{ background-color: #cd6155; }}
|
||||
|
||||
#ConnectButton:disabled, #DisconnectButton:disabled {{
|
||||
background-color: #546e7a;
|
||||
color: #90a4ae;
|
||||
background-color: #546e7a; color: #90a4ae;
|
||||
}}
|
||||
|
||||
#RefreshButton, #StartSwapButton {{ background-color: #27ae60; color: white; border: none; }}
|
||||
|
|
@ -210,9 +754,126 @@ def get_dark_theme_styles(scale=1.0):
|
|||
#ResetButton:hover, #AbortSwapButton:hover {{ background-color: #cd6155; }}
|
||||
#SendAudioButton {{ background-color: #3498db; color: white; border: none; font-size: {max(10, int(14 * scale))}px; }}
|
||||
#SendAudioButton:hover {{ background-color: #5dade2; }}
|
||||
|
||||
QLabel[status="present"] {{ background-color: #2ecc71; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
QLabel[status="absent"] {{ background-color: #e74c3c; color: white; border-radius: {int(4*scale)}px; padding: {int(3*scale)}px; }}
|
||||
QLabel[alarm="active"] {{ background-color: #e74c3c; color: white; font-weight: bold; border-radius: {int(4*scale)}px; padding: {int(2*scale)}px; }}
|
||||
QLabel[alarm="inactive"] {{ background-color: transparent; color: #f0f0f0; }}
|
||||
QGroupBox#ChamberWidget {{ border: 2px solid #3498db; }}
|
||||
"""
|
||||
QGroupBox#ChamberWidget {{ border: 2px solid #3498db; }}
|
||||
|
||||
QLabel#TimestampTitleLabel {{
|
||||
font-size: {max(9, int(11 * scale))}pt;
|
||||
font-weight: bold;
|
||||
}}
|
||||
QLineEdit#TimestampDataField {{
|
||||
font-size: {max(11, int(13 * scale))}pt;
|
||||
font-weight: bold;
|
||||
color: #f0f0f0;
|
||||
}}
|
||||
|
||||
QGroupBox#ChamberWidget QFormLayout QLabel {{
|
||||
font-size: {max(10, int(12 * scale))}px;
|
||||
color: #AAAAAA;
|
||||
}}
|
||||
QGroupBox#ChamberWidget QLineEdit#BatIdField {{
|
||||
font-size: {max(14, int(16 * scale))}px;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}}
|
||||
QGroupBox#ChamberWidget QLineEdit#DataField {{
|
||||
font-size: {max(13, int(14 * scale))}px;
|
||||
color: #E0E0E0;
|
||||
}}
|
||||
QGroupBox#ChamberWidget QLineEdit#DoorStatusField {{
|
||||
font-size: {max(12, int(14 * scale))}px;
|
||||
font-weight: bold;
|
||||
color: #E0E0E0;
|
||||
}}
|
||||
|
||||
/* ---------- ABOUT CARD (DARK) ---------- */
|
||||
#aboutCard {{
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 12px;
|
||||
}}
|
||||
#aboutCard #title {{
|
||||
color: #eaeaea;
|
||||
font-size: {max(16, int(18 * scale))}pt;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2px;
|
||||
}}
|
||||
#aboutCard #subtitle {{
|
||||
color: #aab4c0;
|
||||
font-size: {max(9, int(11 * scale))}pt;
|
||||
font-weight: 500;
|
||||
}}
|
||||
#aboutCard #kvLabel {{
|
||||
color: #b6b6b6;
|
||||
font-weight: 600;
|
||||
}}
|
||||
#aboutCard #badge {{
|
||||
color: #eaf3ff;
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #2563eb, stop:1 #7c3aed);
|
||||
border-radius: 999px;
|
||||
padding: {int(5*scale)}px {int(12*scale)}px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.3px;
|
||||
font-size: {max(8, int(10*scale))}pt;
|
||||
text-transform: uppercase;
|
||||
}}
|
||||
#aboutCard #divider {{
|
||||
background: #3a3a3a;
|
||||
margin: {int(6*scale)}px 0 {int(8*scale)}px 0;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
border: none;
|
||||
}}
|
||||
#aboutCard #footer {{
|
||||
color: #7e8895;
|
||||
font-size: {max(8, int(10*scale))}pt;
|
||||
}}
|
||||
#aboutCard a {{
|
||||
color: #6aa9ff; text-decoration: none;
|
||||
}}
|
||||
#aboutCard a:hover {{ color: #82b1ff; text-decoration: underline; }}
|
||||
|
||||
/* ---------- HELP CARD (DARK) ---------- */
|
||||
#helpCard {{
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 12px;
|
||||
}}
|
||||
|
||||
#helpTitle {{ color: #eaeaea; font-weight: 700; font-size: 18px; }}
|
||||
#helpSubtitle {{ color: #c8c8c8; font-size: 12px; }}
|
||||
#helpDivider {{ background: #3a3a3a; min-height: 1px; max-height: 1px; border: none; }}
|
||||
#sectionTitle {{ color: #e6e6e6; font-weight: 600; margin-top: 6px; }}
|
||||
#bodyText {{ color: #dcdcdc; }}
|
||||
|
||||
/* Callouts (dark theme) */
|
||||
#tipBox {{
|
||||
background: #1f3326;
|
||||
border: 1px solid #62d39b;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
#tipTitle {{ color: #a8f5c9; font-weight: 700; }}
|
||||
#tipText {{ color: #d6ffe9; }}
|
||||
|
||||
#warnBox {{
|
||||
background: #3b2e1b;
|
||||
border: 1px solid #ffb74d;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
#warnTitle {{ color: #ffd561; font-weight: 700; }}
|
||||
#warnText {{ color: #f0e0c0; }}
|
||||
|
||||
#link {{
|
||||
color: #007bff; /* Standard Bootstrap blue */
|
||||
text-decoration: none;
|
||||
}}
|
||||
#link:hover {{
|
||||
color: #0056b3; /* Darker blue on hover */
|
||||
text-decoration: underline;
|
||||
}}
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -17,24 +17,6 @@ class ChamberWidget(QGroupBox):
|
|||
self.setObjectName("ChamberWidget")
|
||||
self.setFont(QFont("Arial", max(8, int(9 * scale)), QFont.Weight.Bold))
|
||||
|
||||
# --- ADD THIS STYLESHEET TO CONTROL FONT SIZES ---
|
||||
self.setStyleSheet(f"""
|
||||
QFormLayout QLabel {{
|
||||
font-size: {max(10, int(12 * scale))}px;
|
||||
color: #AAAAAA;
|
||||
}}
|
||||
QLineEdit#BatIdField {{
|
||||
font-size: {max(14, int(16 * scale))}px;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}}
|
||||
QLineEdit#DataField {{
|
||||
font-size: {max(13, int(14 * scale))}px;
|
||||
color: #E0E0E0;
|
||||
}}
|
||||
""")
|
||||
# --- END OF STYLESHEET ---
|
||||
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(max(2, int(4 * scale)))
|
||||
|
||||
|
|
@ -90,7 +72,7 @@ class ChamberWidget(QGroupBox):
|
|||
self.chg_temp_field.setObjectName("DataField")
|
||||
|
||||
self.door_status_field = self._create_data_field(scale)
|
||||
self.door_status_field.setObjectName("DataField")
|
||||
self.door_status_field.setObjectName("DoorStatusField")
|
||||
|
||||
self.charger_fault_field = self._create_data_field(scale)
|
||||
self.charger_fault_field.setObjectName("DataField")
|
||||
|
|
|
|||
Loading…
Reference in New Issue