Files
CalibratorLauncher/widgets/tableoverlaywidget.cpp
2026-01-02 19:20:35 +09:00

362 lines
9.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "tableoverlaywidget.h"
#include <QPropertyAnimation>
#include <QGraphicsOpacityEffect>
#include <QScrollBar>
#include <QDebug>
TableOverlayWidget::TableOverlayWidget(QWidget *parent)
: QWidget(parent), m_isVisible(false)
{
setupUI();
hide(); // 初始隐藏
}
void TableOverlayWidget::setupUI()
{
// 设置浮层属性
setAttribute(Qt::WA_StyledBackground);
setStyleSheet("TableOverlayWidget { background: transparent; }");
// 主布局
auto *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
// 左侧标签栏滚动区域
m_tabScrollArea = new QScrollArea(this);
m_tabScrollArea->setFixedWidth(130);
m_tabScrollArea->setWidgetResizable(true);
m_tabScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_tabScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_tabScrollArea->setStyleSheet(
"QScrollArea { "
" background: #34495e; "
" border-right: 1px solid #2c3e50; "
" border: none; "
"}"
"QScrollBar:vertical { "
" background: #2c3e50; "
" width: 10px; "
" margin: 0px; "
"}"
"QScrollBar::handle:vertical { "
" background: #546e7a; "
" min-height: 20px; "
" border-radius: 5px; "
"}"
"QScrollBar::handle:vertical:hover { "
" background: #607d8b; "
"}"
"QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { "
" height: 0px; "
"}"
"QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { "
" background: none; "
"}");
// 标签栏容器
m_tabBar = new QWidget();
m_tabBar->setStyleSheet(
"QWidget { "
" background: #34495e; "
"}");
m_tabLayout = new QVBoxLayout(m_tabBar);
m_tabLayout->setContentsMargins(8, 12, 8, 12);
m_tabLayout->setSpacing(6);
m_tabLayout->setAlignment(Qt::AlignTop);
m_tabScrollArea->setWidget(m_tabBar);
mainLayout->addWidget(m_tabScrollArea);
// 内容容器(右侧)
m_container = new QWidget(this);
m_container->setStyleSheet(
"QWidget { "
" background: #f5f5f5; "
" border: none; "
" border-top-right-radius: 10px; "
" border-bottom-right-radius: 10px; "
"}");
auto *containerLayout = new QVBoxLayout(m_container);
containerLayout->setContentsMargins(0, 0, 0, 0);
containerLayout->setSpacing(0);
// 标题栏
auto *headerWidget = new QWidget(this);
headerWidget->setStyleSheet(
"QWidget { "
" background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #3498db, stop:1 #2980b9); "
" border-top-left-radius: 0px; "
" border-top-right-radius: 10px; "
"}");
auto *headerLayout = new QHBoxLayout(headerWidget);
headerLayout->setContentsMargins(20, 10, 10, 10);
headerLayout->setSpacing(8);
m_titleLabel = new QLabel("表格", this);
m_titleLabel->setStyleSheet(
"QLabel { "
" color: white; "
" font-size: 14pt; "
" font-weight: bold; "
" background: transparent; "
"}");
headerLayout->addWidget(m_titleLabel);
headerLayout->addStretch();
// 关闭按钮 - 正方形圆角,图标居中
m_closeBtn = new QPushButton("×", this);
m_closeBtn->setFixedSize(32, 32);
m_closeBtn->setCursor(Qt::PointingHandCursor);
m_closeBtn->setStyleSheet(
"QPushButton { "
" background: rgba(255,255,255,0.2); "
" color: white; "
" border: none; "
" border-radius: 6px; "
" font-size: 20px; "
" font-weight: normal; "
" text-align: center; "
" padding: 0px; "
" margin: 0px; "
"}"
"QPushButton:hover { background: rgba(255,255,255,0.35); }"
"QPushButton:pressed { background: rgba(255,255,255,0.5); }");
connect(m_closeBtn, &QPushButton::clicked, this, &TableOverlayWidget::onCloseButtonClicked);
headerLayout->addWidget(m_closeBtn);
containerLayout->addWidget(headerWidget);
// 内容堆栈
m_contentStack = new QStackedWidget(this);
m_contentStack->setStyleSheet(
"QStackedWidget { "
" background: white; "
" border: none; "
"}");
containerLayout->addWidget(m_contentStack, 1);
mainLayout->addWidget(m_container, 1);
// 设置默认大小占父容器的70%宽度90%高度)
setMinimumWidth(600);
setMaximumWidth(1200);
}
void TableOverlayWidget::addTable(const QString &tableId, const QString &tableName, QWidget *tableWidget)
{
if (m_tables.contains(tableId))
{
qDebug() << "Table already exists:" << tableId;
return;
}
TableTab tab;
tab.id = tableId;
tab.name = tableName;
tab.widget = tableWidget;
// 创建标签按钮
tab.tabButton = new QPushButton(tableName, m_tabBar);
tab.tabButton->setFixedHeight(48);
tab.tabButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
tab.tabButton->setProperty("tableId", tableId);
tab.tabButton->setCursor(Qt::PointingHandCursor);
tab.tabButton->setStyleSheet(
"QPushButton {"
" background: #455a64;"
" color: #ecf0f1;"
" border: none;"
" border-radius: 6px;"
" padding: 6px 6px;"
" font-size: 9.5pt;"
" font-weight: 500;"
" text-align: center;"
" border-left: 3px solid transparent;"
"}"
"QPushButton:hover {"
" background: #546e7a;"
" color: white;"
"}"
"QPushButton:checked {"
" background: #2980b9;"
" color: white;"
" font-weight: bold;"
" border-left: 3px solid #1976d2;"
"}"
"QPushButton:pressed {"
" background: #21618c;"
"}");
tab.tabButton->setCheckable(true);
connect(tab.tabButton, &QPushButton::clicked, this, &TableOverlayWidget::onTabButtonClicked);
// 添加到布局
m_tabLayout->addWidget(tab.tabButton);
// 添加到内容堆栈
m_contentStack->addWidget(tableWidget);
m_tables[tableId] = tab;
// 如果是第一个表格,自动显示
if (m_tables.size() == 1)
{
showTable(tableId);
}
}
void TableOverlayWidget::showTable(const QString &tableId)
{
if (!m_tables.contains(tableId))
{
qDebug() << "Table not found:" << tableId;
return;
}
// 取消之前的选中状态
if (!m_currentTableId.isEmpty() && m_tables.contains(m_currentTableId))
{
m_tables[m_currentTableId].tabButton->setChecked(false);
}
// 切换到新表格
m_currentTableId = tableId;
const TableTab &tab = m_tables[tableId];
tab.tabButton->setChecked(true);
m_contentStack->setCurrentWidget(tab.widget);
m_titleLabel->setText(tab.name);
emit tableChanged(tableId);
}
void TableOverlayWidget::removeTable(const QString &tableId)
{
if (!m_tables.contains(tableId))
return;
TableTab tab = m_tables.take(tableId);
// 移除按钮
m_tabLayout->removeWidget(tab.tabButton);
tab.tabButton->deleteLater();
// 移除内容
m_contentStack->removeWidget(tab.widget);
// 如果删除的是当前表格,切换到第一个
if (m_currentTableId == tableId && !m_tables.isEmpty())
{
showTable(m_tables.firstKey());
}
else if (m_tables.isEmpty())
{
m_currentTableId.clear();
hideOverlay();
}
}
void TableOverlayWidget::clearTables()
{
// 清除所有表格
for (const QString &tableId : m_tables.keys())
{
removeTable(tableId);
}
m_currentTableId.clear();
}
void TableOverlayWidget::showOverlay()
{
if (m_isVisible || m_tables.isEmpty())
return;
// 如果当前没有选中的表格,显示第一个
if (m_currentTableId.isEmpty() && !m_tables.isEmpty())
{
showTable(m_tables.firstKey());
}
m_isVisible = true;
m_container->show();
m_tabBar->show();
show();
animateShow();
}
void TableOverlayWidget::hideOverlay()
{
if (!m_isVisible)
return;
m_isVisible = false;
animateHide();
}
void TableOverlayWidget::toggleOverlay()
{
if (m_isVisible)
hideOverlay();
else
showOverlay();
}
void TableOverlayWidget::onTabButtonClicked()
{
QPushButton *btn = qobject_cast<QPushButton *>(sender());
if (!btn)
return;
QString tableId = btn->property("tableId").toString();
if (!tableId.isEmpty())
{
showTable(tableId);
}
}
void TableOverlayWidget::onCloseButtonClicked()
{
hideOverlay();
emit closed();
}
void TableOverlayWidget::updateTabButtons()
{
for (const TableTab &tab : m_tables)
{
tab.tabButton->setChecked(tab.id == m_currentTableId);
}
}
void TableOverlayWidget::animateShow()
{
// 淡入动画
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(this);
setGraphicsEffect(effect);
QPropertyAnimation *animation = new QPropertyAnimation(effect, "opacity");
animation->setDuration(200);
animation->setStartValue(0.0);
animation->setEndValue(1.0);
animation->setEasingCurve(QEasingCurve::OutCubic);
animation->start(QPropertyAnimation::DeleteWhenStopped);
}
void TableOverlayWidget::animateHide()
{
// 淡出动画
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(this);
setGraphicsEffect(effect);
QPropertyAnimation *animation = new QPropertyAnimation(effect, "opacity");
animation->setDuration(150);
animation->setStartValue(1.0);
animation->setEndValue(0.0);
animation->setEasingCurve(QEasingCurve::InCubic);
connect(animation, &QPropertyAnimation::finished, this, &TableOverlayWidget::hide);
animation->start(QPropertyAnimation::DeleteWhenStopped);
}