939 lines
30 KiB
C++
939 lines
30 KiB
C++
|
|
#include "lightstripmanager.h"
|
|||
|
|
#include <QThread>
|
|||
|
|
// 如果不再需要可以删除: #include <QRandomGenerator>
|
|||
|
|
|
|||
|
|
LightStripManager::LightStripManager(QWidget *parent)
|
|||
|
|
: QWidget(parent)
|
|||
|
|
, settings(new QSettings("LightStripManager", "Config", this))
|
|||
|
|
, columnsPerRow(4)
|
|||
|
|
, resizeTimer(new QTimer(this))
|
|||
|
|
{
|
|||
|
|
setupUI();
|
|||
|
|
loadSnList();
|
|||
|
|
|
|||
|
|
// 设置窗口属性
|
|||
|
|
setWindowTitle("灯条SN管理器");
|
|||
|
|
setWindowIcon(QIcon(":/icons/lightstrip.png"));
|
|||
|
|
|
|||
|
|
// 设置初始窗口大小和位置
|
|||
|
|
resize(1000, 650);
|
|||
|
|
|
|||
|
|
// 居中显示到父窗口
|
|||
|
|
if (parent) {
|
|||
|
|
QWidget *parentWidget = qobject_cast<QWidget*>(parent);
|
|||
|
|
if (parentWidget) {
|
|||
|
|
QRect parentGeometry = parentWidget->geometry();
|
|||
|
|
int x = parentGeometry.x() + (parentGeometry.width() - width()) / 2;
|
|||
|
|
int y = parentGeometry.y() + (parentGeometry.height() - height()) / 2;
|
|||
|
|
move(x, y);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 如果没有父窗口,则居中到屏幕
|
|||
|
|
QScreen *screen = QGuiApplication::primaryScreen();
|
|||
|
|
if (screen) {
|
|||
|
|
QRect screenGeometry = screen->geometry();
|
|||
|
|
int x = (screenGeometry.width() - width()) / 2;
|
|||
|
|
int y = (screenGeometry.height() - height()) / 2;
|
|||
|
|
move(x, y);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置最小尺寸
|
|||
|
|
setMinimumSize(700, 500);
|
|||
|
|
|
|||
|
|
// 彻底修复背景透明问题
|
|||
|
|
setStyleSheet(
|
|||
|
|
"QWidget { "
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
"} "
|
|||
|
|
"QGroupBox { "
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
"} "
|
|||
|
|
"QSplitter { "
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
setAutoFillBackground(true);
|
|||
|
|
|
|||
|
|
// 设置窗口属性,确保有标题栏和关闭按钮
|
|||
|
|
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
|
|||
|
|
|
|||
|
|
// 连接调整大小定时器
|
|||
|
|
resizeTimer->setSingleShot(true);
|
|||
|
|
resizeTimer->setInterval(100);
|
|||
|
|
connect(resizeTimer, &QTimer::timeout, this, &LightStripManager::applyResponsiveLayout);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
LightStripManager::~LightStripManager()
|
|||
|
|
{
|
|||
|
|
saveSnList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::setupUI()
|
|||
|
|
{
|
|||
|
|
mainLayout = new QVBoxLayout(this);
|
|||
|
|
mainLayout->setSpacing(15);
|
|||
|
|
mainLayout->setContentsMargins(20, 20, 20, 20);
|
|||
|
|
|
|||
|
|
// 创建主分割器
|
|||
|
|
mainSplitter = new QSplitter(Qt::Vertical, this);
|
|||
|
|
mainLayout->addWidget(mainSplitter);
|
|||
|
|
|
|||
|
|
// 添加顶部关闭按钮区域
|
|||
|
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
|||
|
|
topLayout->addStretch();
|
|||
|
|
|
|||
|
|
QPushButton *closeBtn = new QPushButton("关闭");
|
|||
|
|
closeBtn->setMaximumWidth(80);
|
|||
|
|
closeBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #f44336; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #d32f2f; }"
|
|||
|
|
);
|
|||
|
|
connect(closeBtn, &QPushButton::clicked, this, &QWidget::close);
|
|||
|
|
topLayout->addWidget(closeBtn);
|
|||
|
|
|
|||
|
|
mainLayout->addLayout(topLayout);
|
|||
|
|
|
|||
|
|
// 设置各个区域
|
|||
|
|
setupControlPanel();
|
|||
|
|
setupSnDisplayArea();
|
|||
|
|
setupLightControlArea();
|
|||
|
|
|
|||
|
|
// 设置分割器比例
|
|||
|
|
mainSplitter->setStretchFactor(0, 0); // 控制面板固定高度
|
|||
|
|
mainSplitter->setStretchFactor(1, 1); // SN显示区域可伸缩
|
|||
|
|
mainSplitter->setStretchFactor(2, 0); // 点亮控制区域固定高度
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::setupControlPanel()
|
|||
|
|
{
|
|||
|
|
controlGroup = new QGroupBox("控制面板", this);
|
|||
|
|
controlGroup->setStyleSheet(
|
|||
|
|
"QGroupBox { "
|
|||
|
|
" color: #000000; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
" padding-top: 15px; "
|
|||
|
|
" border: 2px solid #ddd; "
|
|||
|
|
" border-radius: 8px; "
|
|||
|
|
" margin-top: 10px; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
controlGroup->setMaximumHeight(120);
|
|||
|
|
|
|||
|
|
QVBoxLayout *controlMainLayout = new QVBoxLayout(controlGroup);
|
|||
|
|
|
|||
|
|
// 第一行:选择和删除操作
|
|||
|
|
QHBoxLayout *row1Layout = new QHBoxLayout();
|
|||
|
|
|
|||
|
|
selectAllBtn = new QPushButton("全选");
|
|||
|
|
selectAllBtn->setMinimumHeight(35);
|
|||
|
|
selectAllBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #2196F3; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #1976D2; }"
|
|||
|
|
);
|
|||
|
|
connect(selectAllBtn, &QPushButton::clicked, this, &LightStripManager::onSelectAllClicked);
|
|||
|
|
|
|||
|
|
deselectAllBtn = new QPushButton("取消全选");
|
|||
|
|
deselectAllBtn->setMinimumHeight(35);
|
|||
|
|
deselectAllBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #FF9800; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #F57C00; }"
|
|||
|
|
);
|
|||
|
|
connect(deselectAllBtn, &QPushButton::clicked, this, &LightStripManager::onDeselectAllClicked);
|
|||
|
|
|
|||
|
|
deleteSelectedBtn = new QPushButton("删除选中");
|
|||
|
|
deleteSelectedBtn->setMinimumHeight(35);
|
|||
|
|
deleteSelectedBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #f44336; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #d32f2f; }"
|
|||
|
|
);
|
|||
|
|
connect(deleteSelectedBtn, &QPushButton::clicked, this, &LightStripManager::onDeleteSelectedClicked);
|
|||
|
|
|
|||
|
|
clearAllBtn = new QPushButton("清空全部");
|
|||
|
|
clearAllBtn->setMinimumHeight(35);
|
|||
|
|
clearAllBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #9E9E9E; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #757575; }"
|
|||
|
|
);
|
|||
|
|
connect(clearAllBtn, &QPushButton::clicked, this, &LightStripManager::onClearSnListClicked);
|
|||
|
|
|
|||
|
|
refreshBtn = new QPushButton("刷新");
|
|||
|
|
refreshBtn->setMinimumHeight(35);
|
|||
|
|
refreshBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #4CAF50; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 8px 16px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #388E3C; }"
|
|||
|
|
);
|
|||
|
|
connect(refreshBtn, &QPushButton::clicked, this, &LightStripManager::onRefreshClicked);
|
|||
|
|
|
|||
|
|
row1Layout->addWidget(selectAllBtn);
|
|||
|
|
row1Layout->addWidget(deselectAllBtn);
|
|||
|
|
row1Layout->addWidget(deleteSelectedBtn);
|
|||
|
|
row1Layout->addWidget(clearAllBtn);
|
|||
|
|
row1Layout->addWidget(refreshBtn);
|
|||
|
|
row1Layout->addStretch();
|
|||
|
|
|
|||
|
|
// 统计标签
|
|||
|
|
snCountLabel = new QLabel("已发现灯条: 0 个");
|
|||
|
|
snCountLabel->setStyleSheet(
|
|||
|
|
"QLabel { "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
" color: #2196F3; "
|
|||
|
|
" padding: 5px; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
row1Layout->addWidget(snCountLabel);
|
|||
|
|
|
|||
|
|
controlMainLayout->addLayout(row1Layout);
|
|||
|
|
|
|||
|
|
// 第二行:搜索和手动添加
|
|||
|
|
QHBoxLayout *row2Layout = new QHBoxLayout();
|
|||
|
|
|
|||
|
|
QLabel *searchLabel = new QLabel("搜索:");
|
|||
|
|
searchLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(searchLabel);
|
|||
|
|
searchEdit = new QLineEdit();
|
|||
|
|
searchEdit->setPlaceholderText("输入SN进行搜索...");
|
|||
|
|
searchEdit->setMinimumHeight(30);
|
|||
|
|
searchEdit->setStyleSheet(
|
|||
|
|
"QLineEdit { "
|
|||
|
|
" color: #000000; "
|
|||
|
|
" border: 2px solid #ddd; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 5px 10px; "
|
|||
|
|
" font-size: 12px; "
|
|||
|
|
"} "
|
|||
|
|
"QLineEdit:focus { border-color: #2196F3; }"
|
|||
|
|
);
|
|||
|
|
connect(searchEdit, &QLineEdit::textChanged, this, &LightStripManager::onSearchTextChanged);
|
|||
|
|
row2Layout->addWidget(searchEdit);
|
|||
|
|
|
|||
|
|
QLabel *manualAddLabel = new QLabel("手动添加:");
|
|||
|
|
manualAddLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(manualAddLabel);
|
|||
|
|
manualSnEdit = new QLineEdit();
|
|||
|
|
manualSnEdit->setPlaceholderText("输入SN手动添加...");
|
|||
|
|
manualSnEdit->setMinimumHeight(30);
|
|||
|
|
manualSnEdit->setStyleSheet(
|
|||
|
|
"QLineEdit { "
|
|||
|
|
" color: #000000; "
|
|||
|
|
" border: 2px solid #ddd; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 5px 10px; "
|
|||
|
|
" font-size: 12px; "
|
|||
|
|
"} "
|
|||
|
|
"QLineEdit:focus { border-color: #2196F3; }"
|
|||
|
|
);
|
|||
|
|
row2Layout->addWidget(manualSnEdit);
|
|||
|
|
|
|||
|
|
addSnBtn = new QPushButton("添加");
|
|||
|
|
addSnBtn->setMinimumHeight(30);
|
|||
|
|
addSnBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #4CAF50; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" padding: 5px 15px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #388E3C; }"
|
|||
|
|
);
|
|||
|
|
connect(addSnBtn, &QPushButton::clicked, this, &LightStripManager::onAddSnManuallyClicked);
|
|||
|
|
row2Layout->addWidget(addSnBtn);
|
|||
|
|
|
|||
|
|
controlMainLayout->addLayout(row2Layout);
|
|||
|
|
|
|||
|
|
mainSplitter->addWidget(controlGroup);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::setupSnDisplayArea()
|
|||
|
|
{
|
|||
|
|
snDisplayGroup = new QGroupBox("灯条SN列表", this);
|
|||
|
|
snDisplayGroup->setStyleSheet(
|
|||
|
|
"QGroupBox { "
|
|||
|
|
" color: #000000; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
" padding-top: 15px; "
|
|||
|
|
" border: 2px solid #ddd; "
|
|||
|
|
" border-radius: 8px; "
|
|||
|
|
" margin-top: 10px; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
QVBoxLayout *snDisplayLayout = new QVBoxLayout(snDisplayGroup);
|
|||
|
|
|
|||
|
|
// 创建滚动区域
|
|||
|
|
snScrollArea = new QScrollArea(this);
|
|||
|
|
snScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|||
|
|
snScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|||
|
|
snScrollArea->setWidgetResizable(true);
|
|||
|
|
snScrollArea->setStyleSheet(
|
|||
|
|
"QScrollArea { "
|
|||
|
|
" border: 1px solid #ddd; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" background-color: #fafafa; "
|
|||
|
|
"} "
|
|||
|
|
"QScrollBar:vertical { "
|
|||
|
|
" border: none; "
|
|||
|
|
" background: #f0f0f0; "
|
|||
|
|
" width: 12px; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
"} "
|
|||
|
|
"QScrollBar::handle:vertical { "
|
|||
|
|
" background: #c0c0c0; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" min-height: 20px; "
|
|||
|
|
"} "
|
|||
|
|
"QScrollBar::handle:vertical:hover { "
|
|||
|
|
" background: #a0a0a0; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 创建容器widget和网格布局
|
|||
|
|
snContainerWidget = new QWidget();
|
|||
|
|
snGridLayout = new QGridLayout(snContainerWidget);
|
|||
|
|
snGridLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
|||
|
|
snGridLayout->setSpacing(15);
|
|||
|
|
snGridLayout->setContentsMargins(15, 15, 15, 15);
|
|||
|
|
|
|||
|
|
snScrollArea->setWidget(snContainerWidget);
|
|||
|
|
snDisplayLayout->addWidget(snScrollArea);
|
|||
|
|
|
|||
|
|
mainSplitter->addWidget(snDisplayGroup);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::setupLightControlArea()
|
|||
|
|
{
|
|||
|
|
lightControlGroup = new QGroupBox("点亮控制", this);
|
|||
|
|
lightControlGroup->setStyleSheet(
|
|||
|
|
"QGroupBox { "
|
|||
|
|
" color: #000000; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
" padding-top: 15px; "
|
|||
|
|
" border: 2px solid #ddd; "
|
|||
|
|
" border-radius: 8px; "
|
|||
|
|
" margin-top: 10px; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
lightControlGroup->setMaximumHeight(150);
|
|||
|
|
|
|||
|
|
QVBoxLayout *lightControlLayout = new QVBoxLayout(lightControlGroup);
|
|||
|
|
|
|||
|
|
// 第一行:颜色和闪烁
|
|||
|
|
QHBoxLayout *row1Layout = new QHBoxLayout();
|
|||
|
|
|
|||
|
|
QLabel *colorLabel = new QLabel("颜色:");
|
|||
|
|
colorLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(colorLabel);
|
|||
|
|
|
|||
|
|
colorCombo = new QComboBox();
|
|||
|
|
colorCombo->addItems({"8-灭", "1-红", "2-黄", "3-蓝", "4-绿", "5-青", "6-白", "7-紫"});
|
|||
|
|
colorCombo->setCurrentIndex(6);
|
|||
|
|
colorCombo->setMinimumHeight(30);
|
|||
|
|
colorCombo->setStyleSheet("QComboBox { color: #000000; } QComboBox QAbstractItemView { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(colorCombo);
|
|||
|
|
|
|||
|
|
// 删除以下随机颜色按钮相关代码:
|
|||
|
|
// randomColorBtn = new QPushButton("随机颜色");
|
|||
|
|
// randomColorBtn->setMinimumHeight(30);
|
|||
|
|
// randomColorBtn->setStyleSheet(...);
|
|||
|
|
// connect(randomColorBtn, &QPushButton::clicked, this, &LightStripManager::onRandomColorClicked);
|
|||
|
|
// row1Layout->addWidget(randomColorBtn);
|
|||
|
|
|
|||
|
|
QLabel *flashLabel = new QLabel("闪烁:");
|
|||
|
|
flashLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(flashLabel);
|
|||
|
|
|
|||
|
|
flashCombo = new QComboBox();
|
|||
|
|
flashCombo->addItems({"0-关闭", "1-开启"});
|
|||
|
|
flashCombo->setCurrentIndex(0);
|
|||
|
|
flashCombo->setMinimumHeight(30);
|
|||
|
|
flashCombo->setStyleSheet("QComboBox { color: #000000; } QComboBox QAbstractItemView { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(flashCombo);
|
|||
|
|
|
|||
|
|
QLabel *soundLabel = new QLabel("声音:");
|
|||
|
|
soundLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(soundLabel);
|
|||
|
|
|
|||
|
|
soundCombo = new QComboBox();
|
|||
|
|
soundCombo->addItems({"0-关闭", "1-开启"});
|
|||
|
|
soundCombo->setCurrentIndex(0);
|
|||
|
|
soundCombo->setMinimumHeight(30);
|
|||
|
|
soundCombo->setStyleSheet("QComboBox { color: #000000; } QComboBox QAbstractItemView { color: #000000; }");
|
|||
|
|
row1Layout->addWidget(soundCombo);
|
|||
|
|
row1Layout->addStretch();
|
|||
|
|
|
|||
|
|
lightControlLayout->addLayout(row1Layout);
|
|||
|
|
|
|||
|
|
// 第二行:时间参数和按钮
|
|||
|
|
QHBoxLayout *row2Layout = new QHBoxLayout();
|
|||
|
|
|
|||
|
|
QLabel *flashIntervalLabel = new QLabel("闪烁间隔(秒):");
|
|||
|
|
flashIntervalLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(flashIntervalLabel);
|
|||
|
|
|
|||
|
|
flashIntervalSpin = new QSpinBox();
|
|||
|
|
flashIntervalSpin->setRange(1, 60);
|
|||
|
|
flashIntervalSpin->setValue(4);
|
|||
|
|
flashIntervalSpin->setMinimumHeight(30);
|
|||
|
|
flashIntervalSpin->setStyleSheet("QSpinBox { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(flashIntervalSpin);
|
|||
|
|
|
|||
|
|
QLabel *lightDurationLabel = new QLabel("点亮时长(秒):");
|
|||
|
|
lightDurationLabel->setStyleSheet("QLabel { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(lightDurationLabel);
|
|||
|
|
|
|||
|
|
lightDurationSpin = new QSpinBox();
|
|||
|
|
lightDurationSpin->setRange(1, 300);
|
|||
|
|
lightDurationSpin->setValue(30);
|
|||
|
|
lightDurationSpin->setMinimumHeight(30);
|
|||
|
|
lightDurationSpin->setStyleSheet("QSpinBox { color: #000000; }");
|
|||
|
|
row2Layout->addWidget(lightDurationSpin);
|
|||
|
|
|
|||
|
|
row2Layout->addStretch();
|
|||
|
|
|
|||
|
|
sendLightSelectedBtn = new QPushButton("点亮选中");
|
|||
|
|
sendLightSelectedBtn->setMinimumHeight(40);
|
|||
|
|
sendLightSelectedBtn->setMinimumWidth(120);
|
|||
|
|
sendLightSelectedBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #FF9800; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" padding: 10px 20px; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #F57C00; }"
|
|||
|
|
);
|
|||
|
|
connect(sendLightSelectedBtn, &QPushButton::clicked, this, &LightStripManager::onSendLightSelectedClicked);
|
|||
|
|
row2Layout->addWidget(sendLightSelectedBtn);
|
|||
|
|
|
|||
|
|
sendLightAllBtn = new QPushButton("点亮全部");
|
|||
|
|
sendLightAllBtn->setMinimumHeight(40);
|
|||
|
|
sendLightAllBtn->setMinimumWidth(120);
|
|||
|
|
sendLightAllBtn->setStyleSheet(
|
|||
|
|
"QPushButton { "
|
|||
|
|
" background-color: #4CAF50; "
|
|||
|
|
" color: white; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" padding: 10px 20px; "
|
|||
|
|
" border-radius: 6px; "
|
|||
|
|
" font-size: 14px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { background-color: #388E3C; }"
|
|||
|
|
);
|
|||
|
|
connect(sendLightAllBtn, &QPushButton::clicked, this, &LightStripManager::onSendLightAllClicked);
|
|||
|
|
row2Layout->addWidget(sendLightAllBtn);
|
|||
|
|
|
|||
|
|
lightControlLayout->addLayout(row2Layout);
|
|||
|
|
|
|||
|
|
mainSplitter->addWidget(lightControlGroup);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::addSnToList(const QString &sn)
|
|||
|
|
{
|
|||
|
|
if (uniqueSnSet.contains(sn)) {
|
|||
|
|
return; // 已存在,不重复添加
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uniqueSnSet.insert(sn);
|
|||
|
|
|
|||
|
|
// 创建SN widget
|
|||
|
|
QWidget *lightStripWidget = createSnWidget(sn);
|
|||
|
|
lightStripWidgets.append(lightStripWidget);
|
|||
|
|
|
|||
|
|
// 应用响应式布局
|
|||
|
|
applyResponsiveLayout();
|
|||
|
|
|
|||
|
|
// 更新计数
|
|||
|
|
updateSnCount();
|
|||
|
|
|
|||
|
|
// 保存到设置
|
|||
|
|
saveSnList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QWidget* LightStripManager::createSnWidget(const QString &sn)
|
|||
|
|
{
|
|||
|
|
// 创建灯条widget容器
|
|||
|
|
QWidget *lightStripWidget = new QWidget();
|
|||
|
|
lightStripWidget->setFixedSize(200, 90); // 适中的尺寸
|
|||
|
|
lightStripWidget->setStyleSheet(
|
|||
|
|
"QWidget { "
|
|||
|
|
" background-color: white; "
|
|||
|
|
" border: 2px solid #e0e0e0; "
|
|||
|
|
" border-radius: 10px; "
|
|||
|
|
" margin: 5px; "
|
|||
|
|
"} "
|
|||
|
|
"QWidget:hover { "
|
|||
|
|
" border-color: #2196F3; "
|
|||
|
|
" background-color: #f5f5f5; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 创建垂直布局
|
|||
|
|
QVBoxLayout *itemLayout = new QVBoxLayout(lightStripWidget);
|
|||
|
|
itemLayout->setContentsMargins(10, 10, 10, 10);
|
|||
|
|
itemLayout->setSpacing(8);
|
|||
|
|
|
|||
|
|
// 创建复选框
|
|||
|
|
QCheckBox *checkBox = new QCheckBox();
|
|||
|
|
checkBox->setStyleSheet(
|
|||
|
|
"QCheckBox { "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 12px; "
|
|||
|
|
"} "
|
|||
|
|
"QCheckBox::indicator { "
|
|||
|
|
" width: 20px; "
|
|||
|
|
" height: 20px; "
|
|||
|
|
"} "
|
|||
|
|
"QCheckBox::indicator:unchecked { "
|
|||
|
|
" border: 2px solid #ccc; "
|
|||
|
|
" border-radius: 4px; "
|
|||
|
|
" background-color: white; "
|
|||
|
|
"} "
|
|||
|
|
"QCheckBox::indicator:checked { "
|
|||
|
|
" border: 2px solid #4CAF50; "
|
|||
|
|
" border-radius: 4px; "
|
|||
|
|
" background-color: #4CAF50; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
connect(checkBox, &QCheckBox::stateChanged, this, &LightStripManager::onCheckBoxStateChanged);
|
|||
|
|
lightStripCheckBoxes.append(checkBox);
|
|||
|
|
|
|||
|
|
// 创建SN标签
|
|||
|
|
QLabel *snLabel = new QLabel(sn);
|
|||
|
|
snLabel->setAlignment(Qt::AlignCenter);
|
|||
|
|
snLabel->setStyleSheet(
|
|||
|
|
"QLabel { "
|
|||
|
|
" color: #333; "
|
|||
|
|
" font-weight: bold; "
|
|||
|
|
" font-size: 11px; " // 稍微减小字体
|
|||
|
|
" background-color: #f0f8ff; "
|
|||
|
|
" border: 1px solid #ddd; "
|
|||
|
|
" border-radius: 5px; "
|
|||
|
|
" padding: 6px 4px; " // 减少左右padding
|
|||
|
|
" min-height: 12px; " // 相应调整最小高度
|
|||
|
|
" line-height: 0.3; " // 稍微紧凑的行高
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
snLabel->setWordWrap(true);
|
|||
|
|
|
|||
|
|
// 添加到布局
|
|||
|
|
itemLayout->addWidget(checkBox, 0, Qt::AlignCenter);
|
|||
|
|
itemLayout->addWidget(snLabel);
|
|||
|
|
itemLayout->addStretch();
|
|||
|
|
|
|||
|
|
return lightStripWidget;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::applyResponsiveLayout()
|
|||
|
|
{
|
|||
|
|
// 清空当前布局
|
|||
|
|
QLayoutItem *item;
|
|||
|
|
while ((item = snGridLayout->takeAt(0)) != nullptr) {
|
|||
|
|
// 不删除widget,只是从布局中移除
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算每行的列数
|
|||
|
|
int containerWidth = snScrollArea->viewport()->width() - 30; // 减去边距
|
|||
|
|
int widgetWidth = 220; // widget宽度 + 间距
|
|||
|
|
columnsPerRow = qMax(1, containerWidth / widgetWidth);
|
|||
|
|
|
|||
|
|
// 重新排列所有widget
|
|||
|
|
for (int i = 0; i < lightStripWidgets.size(); ++i) {
|
|||
|
|
int row = i / columnsPerRow;
|
|||
|
|
int col = i % columnsPerRow;
|
|||
|
|
snGridLayout->addWidget(lightStripWidgets[i], row, col);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::resizeEvent(QResizeEvent *event)
|
|||
|
|
{
|
|||
|
|
QWidget::resizeEvent(event);
|
|||
|
|
resizeTimer->start(); // 延迟应用响应式布局
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onClearSnListClicked()
|
|||
|
|
{
|
|||
|
|
if (uniqueSnSet.isEmpty()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int ret = QMessageBox::question(this, "确认清空",
|
|||
|
|
QString("确定要清空所有 %1 个灯条SN吗?").arg(uniqueSnSet.size()),
|
|||
|
|
QMessageBox::Yes | QMessageBox::No,
|
|||
|
|
QMessageBox::No);
|
|||
|
|
|
|||
|
|
if (ret == QMessageBox::Yes) {
|
|||
|
|
// 清空所有灯条widget
|
|||
|
|
for (QWidget *widget : lightStripWidgets) {
|
|||
|
|
delete widget;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清空列表和集合
|
|||
|
|
lightStripWidgets.clear();
|
|||
|
|
lightStripCheckBoxes.clear();
|
|||
|
|
uniqueSnSet.clear();
|
|||
|
|
|
|||
|
|
// 更新显示
|
|||
|
|
updateSnCount();
|
|||
|
|
updateControlButtons();
|
|||
|
|
|
|||
|
|
// 保存设置
|
|||
|
|
saveSnList();
|
|||
|
|
|
|||
|
|
emit clearAllRequested();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onSelectAllClicked()
|
|||
|
|
{
|
|||
|
|
for (QCheckBox *checkBox : lightStripCheckBoxes) {
|
|||
|
|
checkBox->setChecked(true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onDeselectAllClicked()
|
|||
|
|
{
|
|||
|
|
for (QCheckBox *checkBox : lightStripCheckBoxes) {
|
|||
|
|
checkBox->setChecked(false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onDeleteSelectedClicked()
|
|||
|
|
{
|
|||
|
|
QStringList selectedSns = getSelectedSns();
|
|||
|
|
if (selectedSns.isEmpty()) {
|
|||
|
|
QMessageBox::information(this, "提示", "请先选择要删除的灯条SN。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int ret = QMessageBox::question(this, "确认删除",
|
|||
|
|
QString("确定要删除选中的 %1 个灯条SN吗?").arg(selectedSns.size()),
|
|||
|
|
QMessageBox::Yes | QMessageBox::No,
|
|||
|
|
QMessageBox::No);
|
|||
|
|
|
|||
|
|
if (ret == QMessageBox::Yes) {
|
|||
|
|
// 从后往前删除,避免索引问题
|
|||
|
|
for (int i = lightStripWidgets.size() - 1; i >= 0; --i) {
|
|||
|
|
if (lightStripCheckBoxes[i]->isChecked()) {
|
|||
|
|
// 从集合中移除SN
|
|||
|
|
QLabel *snLabel = lightStripWidgets[i]->findChild<QLabel*>();
|
|||
|
|
if (snLabel) {
|
|||
|
|
uniqueSnSet.remove(snLabel->text());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 删除widget
|
|||
|
|
delete lightStripWidgets[i];
|
|||
|
|
lightStripWidgets.removeAt(i);
|
|||
|
|
lightStripCheckBoxes.removeAt(i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新应用布局
|
|||
|
|
applyResponsiveLayout();
|
|||
|
|
|
|||
|
|
// 更新显示
|
|||
|
|
updateSnCount();
|
|||
|
|
updateControlButtons();
|
|||
|
|
|
|||
|
|
// 保存设置
|
|||
|
|
saveSnList();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onAddSnManuallyClicked()
|
|||
|
|
{
|
|||
|
|
QString sn = manualSnEdit->text().trimmed();
|
|||
|
|
if (sn.isEmpty()) {
|
|||
|
|
QMessageBox msgBox;
|
|||
|
|
msgBox.setWindowTitle("提示");
|
|||
|
|
msgBox.setText("请输入要添加的灯条SN。");
|
|||
|
|
msgBox.setIcon(QMessageBox::Information);
|
|||
|
|
msgBox.setStyleSheet(
|
|||
|
|
"QMessageBox { "
|
|||
|
|
" color: #000000; " // 消息文本颜色设为黑色
|
|||
|
|
"} "
|
|||
|
|
"QPushButton { "
|
|||
|
|
" color: #000000; " // 按钮文字颜色设为黑色
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
" border: 1px solid #ccc; "
|
|||
|
|
" border-radius: 4px; "
|
|||
|
|
" padding: 6px 12px; "
|
|||
|
|
" min-width: 60px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { "
|
|||
|
|
" background-color: #e0e0e0; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:pressed { "
|
|||
|
|
" background-color: #d0d0d0; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
msgBox.exec();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (uniqueSnSet.contains(sn)) {
|
|||
|
|
QMessageBox msgBox;
|
|||
|
|
msgBox.setWindowTitle("提示");
|
|||
|
|
msgBox.setText("该灯条SN已存在。");
|
|||
|
|
msgBox.setIcon(QMessageBox::Information);
|
|||
|
|
msgBox.setStyleSheet(
|
|||
|
|
"QMessageBox { "
|
|||
|
|
" color: #000000; " // 消息文本颜色设为黑色
|
|||
|
|
"} "
|
|||
|
|
"QPushButton { "
|
|||
|
|
" color: #000000; " // 按钮文字颜色设为黑色
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
" border: 1px solid #ccc; "
|
|||
|
|
" border-radius: 4px; "
|
|||
|
|
" padding: 6px 12px; "
|
|||
|
|
" min-width: 60px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { "
|
|||
|
|
" background-color: #e0e0e0; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:pressed { "
|
|||
|
|
" background-color: #d0d0d0; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
msgBox.exec();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
addSnToList(sn);
|
|||
|
|
manualSnEdit->clear();
|
|||
|
|
|
|||
|
|
QMessageBox msgBox;
|
|||
|
|
msgBox.setWindowTitle("成功");
|
|||
|
|
msgBox.setText(QString("已添加灯条SN: %1").arg(sn));
|
|||
|
|
msgBox.setIcon(QMessageBox::Information);
|
|||
|
|
msgBox.setStyleSheet(
|
|||
|
|
"QMessageBox { "
|
|||
|
|
" color: #000000; " // 消息文本颜色设为黑色
|
|||
|
|
"} "
|
|||
|
|
"QPushButton { "
|
|||
|
|
" color: #000000; " // 按钮文字颜色设为黑色
|
|||
|
|
" background-color: #f0f0f0; "
|
|||
|
|
" border: 1px solid #ccc; "
|
|||
|
|
" border-radius: 4px; "
|
|||
|
|
" padding: 6px 12px; "
|
|||
|
|
" min-width: 60px; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:hover { "
|
|||
|
|
" background-color: #e0e0e0; "
|
|||
|
|
"} "
|
|||
|
|
"QPushButton:pressed { "
|
|||
|
|
" background-color: #d0d0d0; "
|
|||
|
|
"}"
|
|||
|
|
);
|
|||
|
|
msgBox.exec();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onSearchTextChanged(const QString &text)
|
|||
|
|
{
|
|||
|
|
filterSnDisplay(text);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onSendLightSelectedClicked()
|
|||
|
|
{
|
|||
|
|
QStringList selectedSns = getSelectedSns();
|
|||
|
|
if (selectedSns.isEmpty()) {
|
|||
|
|
QMessageBox::information(this, "提示", "请先选择要点亮的灯条。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString color = colorCombo->currentText();
|
|||
|
|
bool flash = flashCombo->currentIndex() == 1;
|
|||
|
|
int interval = flashIntervalSpin->value();
|
|||
|
|
int duration = lightDurationSpin->value();
|
|||
|
|
bool sound = soundCombo->currentIndex() == 1;
|
|||
|
|
|
|||
|
|
emit lightControlRequested(selectedSns, color, flash, interval, duration, sound);
|
|||
|
|
|
|||
|
|
QMessageBox::information(this, "发送成功",
|
|||
|
|
QString("已向 %1 个选中的灯条发送点亮指令。").arg(selectedSns.size()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onSendLightAllClicked()
|
|||
|
|
{
|
|||
|
|
if (uniqueSnSet.isEmpty()) {
|
|||
|
|
QMessageBox::information(this, "提示", "没有可点亮的灯条。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QStringList allSns = getAllSns();
|
|||
|
|
QString color = colorCombo->currentText();
|
|||
|
|
bool flash = flashCombo->currentIndex() == 1;
|
|||
|
|
int interval = flashIntervalSpin->value();
|
|||
|
|
int duration = lightDurationSpin->value();
|
|||
|
|
bool sound = soundCombo->currentIndex() == 1;
|
|||
|
|
|
|||
|
|
// 记录总数量用于提示
|
|||
|
|
int totalCount = allSns.size();
|
|||
|
|
|
|||
|
|
// 按20个一批分组发送
|
|||
|
|
const int batchSize = 20;
|
|||
|
|
for (int i = 0; i < allSns.size(); i += batchSize) {
|
|||
|
|
QStringList batch;
|
|||
|
|
for (int j = i; j < qMin(i + batchSize, allSns.size()); ++j) {
|
|||
|
|
batch.append(allSns[j]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送当前批次
|
|||
|
|
emit lightControlRequested(batch, color, flash, interval, duration, sound);
|
|||
|
|
|
|||
|
|
// 添加小延迟避免发送过快(可选)
|
|||
|
|
QThread::msleep(100);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示总数量的提示信息
|
|||
|
|
QMessageBox::information(this, "发送成功",
|
|||
|
|
QString("已向所有灯条发送点亮指令。"));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onCheckBoxStateChanged()
|
|||
|
|
{
|
|||
|
|
updateControlButtons();
|
|||
|
|
emit snSelectionChanged(getSelectedSns());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::onRefreshClicked()
|
|||
|
|
{
|
|||
|
|
// 重新应用响应式布局
|
|||
|
|
applyResponsiveLayout();
|
|||
|
|
|
|||
|
|
// 更新显示
|
|||
|
|
updateSnCount();
|
|||
|
|
updateControlButtons();
|
|||
|
|
|
|||
|
|
QMessageBox::information(this, "刷新完成", "界面已刷新。");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 删除整个函数实现:
|
|||
|
|
// void LightStripManager::onRandomColorClicked()
|
|||
|
|
// {
|
|||
|
|
// int randomIndex = QRandomGenerator::global()->bounded(1, colorCombo->count());
|
|||
|
|
// colorCombo->setCurrentIndex(randomIndex);
|
|||
|
|
// QString selectedColor = colorCombo->currentText();
|
|||
|
|
// QMessageBox::information(this, "随机颜色",
|
|||
|
|
// QString("已随机选择颜色: %1").arg(selectedColor));
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
void LightStripManager::filterSnDisplay(const QString &searchText)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < lightStripWidgets.size(); ++i) {
|
|||
|
|
QWidget *widget = lightStripWidgets[i];
|
|||
|
|
QLabel *snLabel = widget->findChild<QLabel*>();
|
|||
|
|
|
|||
|
|
if (snLabel) {
|
|||
|
|
bool visible = searchText.isEmpty() ||
|
|||
|
|
snLabel->text().contains(searchText, Qt::CaseInsensitive);
|
|||
|
|
widget->setVisible(visible);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新应用布局
|
|||
|
|
applyResponsiveLayout();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::updateSnCount()
|
|||
|
|
{
|
|||
|
|
int count = uniqueSnSet.size();
|
|||
|
|
snCountLabel->setText(QString("已发现灯条: %1 个").arg(count));
|
|||
|
|
|
|||
|
|
// 发出数量变化信号
|
|||
|
|
emit snCountChanged(count);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::updateControlButtons()
|
|||
|
|
{
|
|||
|
|
int selectedCount = getSelectedSns().size();
|
|||
|
|
int totalCount = uniqueSnSet.size();
|
|||
|
|
|
|||
|
|
deleteSelectedBtn->setEnabled(selectedCount > 0);
|
|||
|
|
sendLightSelectedBtn->setEnabled(selectedCount > 0);
|
|||
|
|
sendLightAllBtn->setEnabled(totalCount > 0);
|
|||
|
|
clearAllBtn->setEnabled(totalCount > 0);
|
|||
|
|
selectAllBtn->setEnabled(totalCount > 0);
|
|||
|
|
deselectAllBtn->setEnabled(selectedCount > 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QStringList LightStripManager::getSelectedSns() const
|
|||
|
|
{
|
|||
|
|
QStringList selectedSns;
|
|||
|
|
for (int i = 0; i < lightStripCheckBoxes.size(); ++i) {
|
|||
|
|
if (lightStripCheckBoxes[i]->isChecked()) {
|
|||
|
|
QLabel *snLabel = lightStripWidgets[i]->findChild<QLabel*>();
|
|||
|
|
if (snLabel) {
|
|||
|
|
selectedSns.append(snLabel->text());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return selectedSns;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QStringList LightStripManager::getAllSns() const
|
|||
|
|
{
|
|||
|
|
return uniqueSnSet.values();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int LightStripManager::getSnCount() const
|
|||
|
|
{
|
|||
|
|
return uniqueSnSet.size();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::saveSnList()
|
|||
|
|
{
|
|||
|
|
QStringList snList = uniqueSnSet.values();
|
|||
|
|
settings->setValue("lightStripSnList", snList);
|
|||
|
|
settings->sync();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void LightStripManager::loadSnList()
|
|||
|
|
{
|
|||
|
|
QStringList snList = settings->value("lightStripSnList").toStringList();
|
|||
|
|
for (const QString &sn : snList) {
|
|||
|
|
addSnToList(sn);
|
|||
|
|
}
|
|||
|
|
}
|