259 lines
7.7 KiB
C++
259 lines
7.7 KiB
C++
#include "global.h"
|
|
#include <QStyle>
|
|
#include <QApplication>
|
|
#include <QAbstractButton>
|
|
#include <QPushButton>
|
|
#include <QEvent>
|
|
#include <QKeyEvent>
|
|
#include <QGraphicsDropShadowEffect>
|
|
|
|
// 启动 500ms 闪烁:每 500ms 切换一次动态属性,QSS 据此在 40%↔100% 透明度间切换
|
|
QTimer* startBlink(QWidget* w, const char* prop)
|
|
{
|
|
// 复用已存在的定时器
|
|
if (auto* t = w->findChild<QTimer*>(QString("blink_") + prop))
|
|
return t;
|
|
QTimer* t = new QTimer(w);
|
|
t->setObjectName(QString("blink_") + prop);
|
|
t->setInterval(500);
|
|
QObject::connect(t, &QTimer::timeout, w, [w, prop]() {
|
|
bool cur = w->property(prop).toBool();
|
|
w->setProperty(prop, !cur);
|
|
w->style()->unpolish(w);
|
|
w->style()->polish(w);
|
|
w->update();
|
|
});
|
|
w->setProperty(prop, true);
|
|
t->start();
|
|
return t;
|
|
}
|
|
|
|
void stopBlink(QWidget* w, const char* prop)
|
|
{
|
|
if (auto* t = w->findChild<QTimer*>(QString("blink_") + prop)) {
|
|
t->stop();
|
|
delete t;
|
|
}
|
|
w->setProperty(prop, false);
|
|
w->style()->unpolish(w);
|
|
w->style()->polish(w);
|
|
w->update();
|
|
}
|
|
|
|
QString cancelButtonStyle(int fontPx)
|
|
{
|
|
return QString(
|
|
"QPushButton{font-size:%1px;}"
|
|
"QPushButton:hover,QPushButton:pressed,QPushButton:focus"
|
|
"{background-color:%2;color:#FFFFFF;border:2px solid #FFA6A9;}")
|
|
.arg(fontPx).arg(C::DANGER);
|
|
}
|
|
|
|
// ===================== 按钮焦点光圈 =====================
|
|
ButtonFocusGlow::ButtonFocusGlow(const QColor& glow, QObject* parent)
|
|
: QObject(parent), m_glow(glow)
|
|
{
|
|
}
|
|
|
|
bool ButtonFocusGlow::eventFilter(QObject* obj, QEvent* ev)
|
|
{
|
|
if (ev->type() == QEvent::FocusIn || ev->type() == QEvent::FocusOut) {
|
|
QWidget* w = qobject_cast<QWidget*>(obj);
|
|
if (w && qobject_cast<QPushButton*>(w)) {
|
|
if (ev->type() == QEvent::FocusIn) {
|
|
if (!w->graphicsEffect()) { // 挂一圈发光(偏移 0 → 四周光晕)
|
|
QGraphicsDropShadowEffect* g = new QGraphicsDropShadowEffect(w);
|
|
g->setBlurRadius(40); // 光晕大小(越大越强)
|
|
g->setOffset(0, 0);
|
|
g->setColor(m_glow);
|
|
w->setGraphicsEffect(g);
|
|
}
|
|
} else {
|
|
w->setGraphicsEffect(nullptr); // Qt 会删除旧效果
|
|
}
|
|
}
|
|
}
|
|
return QObject::eventFilter(obj, ev);
|
|
}
|
|
|
|
void installButtonFocusGlow(QApplication* app)
|
|
{
|
|
if (app)
|
|
app->installEventFilter(new ButtonFocusGlow(QColor("#7FBBFF"), app)); // 亮蓝,深色底更醒目
|
|
}
|
|
|
|
// ===================== 方向键(旋钮)隔离 =====================
|
|
ArrowKeyGuard::ArrowKeyGuard(QObject* parent)
|
|
: QObject(parent)
|
|
{
|
|
}
|
|
|
|
bool ArrowKeyGuard::eventFilter(QObject* obj, QEvent* ev)
|
|
{
|
|
if (ev->type() == QEvent::KeyPress) {
|
|
// 只在焦点落在按钮上时拦截:否则 QAbstractButton 会拿方向键去换焦
|
|
QWidget* fw = QApplication::focusWidget();
|
|
if (fw && qobject_cast<QAbstractButton*>(fw)) {
|
|
const int k = static_cast<QKeyEvent*>(ev)->key();
|
|
if (k == Qt::Key_Up || k == Qt::Key_Down
|
|
|| k == Qt::Key_Left || k == Qt::Key_Right)
|
|
return true;
|
|
}
|
|
}
|
|
return QObject::eventFilter(obj, ev);
|
|
}
|
|
|
|
void installArrowKeyGuard(QApplication* app)
|
|
{
|
|
if (app)
|
|
app->installEventFilter(new ArrowKeyGuard(app));
|
|
}
|
|
|
|
QString appStyleSheet()
|
|
{
|
|
const QString s = QString(R"QSS(
|
|
* {
|
|
font-family: "Microsoft YaHei", "PingFang SC", "Source Han Sans CN";
|
|
outline: none;
|
|
}
|
|
QWidget {
|
|
background-color: BG;
|
|
color: TXT;
|
|
}
|
|
QWidget#pageRoot {
|
|
background-color: BG;
|
|
}
|
|
QLabel {
|
|
background: transparent;
|
|
color: TXT;
|
|
}
|
|
QLabel[sub="true"] { color: SUB; }
|
|
QLabel[title="true"] { color: TXT; font-weight: 700; }
|
|
|
|
/* ===== 按钮 ===== */
|
|
QPushButton {
|
|
background-color: PHI;
|
|
color: TXT;
|
|
border: 1px solid BD;
|
|
border-radius: 12px;
|
|
font-size: 40px;
|
|
}
|
|
QPushButton:hover { background-color: PRI; color: TXT; border-color: PRI; }
|
|
QPushButton:pressed { background-color: PRI; color: #FFFFFF; border-color: PRI; }
|
|
QPushButton:checked { background-color: PRI; color: #FFFFFF; border: none; }
|
|
QPushButton:disabled { background-color: DIS; color: DIST; border-color: DIS; }
|
|
|
|
QPushButton[variant="primary"] { background-color: PRI; color: #FFFFFF; border: none; }
|
|
QPushButton[variant="primary"]:disabled { background-color: DIS; color: DIST; }
|
|
QPushButton[variant="danger"] { background-color: DAN; color: #FFFFFF; border: 1px solid DAN; border-radius: 6px; }
|
|
QPushButton[variant="danger"]:disabled { background-color: DIS; color: DIST; border-color: DIS; }
|
|
QPushButton[variant="link"] { background: transparent; color: PRI; border: none; font-size: 22px; }
|
|
QPushButton[variant="estop"] {
|
|
background-color: DAN; color: #FFFFFF; border: 1px solid DAN; border-radius: 6px; font-size: 24px; font-weight: 700;
|
|
}
|
|
|
|
/* ===== 输入框 ===== */
|
|
QLineEdit {
|
|
background-color: BG;
|
|
border: 2px solid BD;
|
|
border-radius: 8px;
|
|
color: TXT;
|
|
font-size: 50px;
|
|
padding: 0 12px;
|
|
}
|
|
QLineEdit:focus { border: 3px solid PRI; }
|
|
|
|
/* ===== 进度条 ===== */
|
|
QProgressBar {
|
|
background-color: PHI;
|
|
border: none;
|
|
border-radius: 4px;
|
|
text-align: center;
|
|
color: #FFFFFF;
|
|
font-size: 40px;
|
|
}
|
|
QProgressBar::chunk { background-color: PRI; border-radius: 4px; }
|
|
|
|
/* ===== 表格 ===== */
|
|
QTableWidget {
|
|
background-color: PAN;
|
|
color: TXT;
|
|
border: 1px solid BD;
|
|
gridline-color: BD;
|
|
font-size: 40px;
|
|
alternate-background-color: #2A3442;
|
|
}
|
|
QHeaderView::section {
|
|
background-color: PHI;
|
|
color: TXT;
|
|
border: none;
|
|
border-right: 1px solid BD;
|
|
border-bottom: 1px solid BD;
|
|
padding: 8px;
|
|
font-size: 40px;
|
|
}
|
|
QTableWidget::item { padding: 6px; }
|
|
QTableWidget::item:selected { background-color: PRI; color: #FFFFFF; }
|
|
|
|
/* ===== 数字键盘 ===== */
|
|
QPushButton[numpad="true"] {
|
|
background-color: PHI; color: TXT; border: 1px solid BD; border-radius: 12px; font-size: 50px;
|
|
}
|
|
QPushButton[numpad="true"]:pressed { background-color: PRI; color: #FFFFFF; }
|
|
|
|
/* ===== 焦点样式(Tab / Shift+Tab / 光标选中:高亮按钮显色 + 边框发亮) ===== */
|
|
QPushButton:focus {
|
|
background-color: PRI;
|
|
color: #FFFFFF;
|
|
border: 4px solid #8ABFFF;
|
|
}
|
|
QPushButton:focus:disabled {
|
|
background-color: DIS; color: DIST; border: 1px solid DIS;
|
|
}
|
|
QPushButton[variant="danger"]:focus,
|
|
QPushButton[variant="estop"]:focus {
|
|
background-color: DAN;
|
|
border: 2px solid #FFA6A9;
|
|
}
|
|
QPushButton[variant="link"]:focus {
|
|
background: transparent;
|
|
color: PRI;
|
|
border: none;
|
|
}
|
|
QPushButton[numpad="true"]:focus {
|
|
background-color: PRI;
|
|
color: #FFFFFF;
|
|
border: 2px solid #8ABFFF;
|
|
}
|
|
|
|
/* ===== 告警文字(红色闪烁由 blink 属性驱动) ===== */
|
|
QLabel[alert="true"] { color: DAN; font-weight: 700; }
|
|
QLabel[alert="true"][blink="false"] { color: rgba(229,72,77,102); }
|
|
QLabel[amber="true"] { color: WAR; font-weight: 700; }
|
|
|
|
/* ===== 数据卡片 ===== */
|
|
QWidget[card="true"] {
|
|
background-color: PAN;
|
|
border: 2px solid BD;
|
|
border-radius: 12px;
|
|
}
|
|
QLabel[cardTitle="true"] { color: TXT; font-weight: 700; }
|
|
)QSS");
|
|
|
|
// 用占位替换(注意:DIST 须在 DIS 之前替换,避免前缀误匹配)
|
|
QString out = s;
|
|
out.replace("DIST", C::DISABLED_T);
|
|
out.replace("DIS", C::DISABLED);
|
|
out.replace("BG", C::BG);
|
|
out.replace("PAN", C::PANEL);
|
|
out.replace("PHI", C::PANEL_HI);
|
|
out.replace("BD", C::BORDER);
|
|
out.replace("TXT", C::TEXT);
|
|
out.replace("SUB", C::TEXT_SUB);
|
|
out.replace("PRI", C::PRIMARY);
|
|
out.replace("SUC", C::SUCCESS);
|
|
out.replace("WAR", C::WARNING);
|
|
out.replace("DAN", C::DANGER);
|
|
return out;
|
|
}
|