增加预览页介绍信息显示

This commit is contained in:
2026-04-08 09:56:25 +08:00
parent f53fee8e5a
commit 028ed1b18d
17 changed files with 1059 additions and 23 deletions

View File

@@ -4,8 +4,14 @@
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
namespace gui {
@@ -50,8 +56,75 @@ EntityPropertySection::EntityPropertySection(QWidget* parent)
form->addRow(QStringLiteral("整体缩放"), m_userScale);
lay->addLayout(form);
m_introHeader = new QWidget(this);
auto* headLay = new QHBoxLayout(m_introHeader);
headLay->setContentsMargins(0, 2, 0, 2);
headLay->setSpacing(6);
m_introToggle = new QToolButton(m_introHeader);
m_introToggle->setAutoRaise(true);
m_introToggle->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_introToggle->setCursor(Qt::PointingHandCursor);
m_introToggle->setToolTip(QStringLiteral("展开或折叠介绍设置"));
m_introToggle->setText(QStringLiteral(""));
m_introToggle->setFixedWidth(22);
auto* introTitleLab = new QLabel(QStringLiteral("介绍"), m_introHeader);
introTitleLab->setStyleSheet(QStringLiteral("QLabel { font-weight: 600; }"));
headLay->addWidget(m_introToggle, 0, Qt::AlignVCenter);
headLay->addWidget(introTitleLab, 1, Qt::AlignVCenter);
m_introContent = new QWidget(this);
auto* introLay = new QVBoxLayout(m_introContent);
introLay->setContentsMargins(8, 4, 0, 0);
introLay->setSpacing(6);
m_introTitle = new QLineEdit(m_introContent);
m_introTitle->setPlaceholderText(QStringLiteral("标题"));
introLay->addWidget(new QLabel(QStringLiteral("标题"), m_introContent));
introLay->addWidget(m_introTitle);
m_introBody = new QTextEdit(m_introContent);
m_introBody->setPlaceholderText(QStringLiteral("正文(纯文本)"));
m_introBody->setMaximumHeight(100);
introLay->addWidget(new QLabel(QStringLiteral("正文"), m_introContent));
introLay->addWidget(m_introBody);
m_introImages = new QListWidget(m_introContent);
m_introImages->setMinimumHeight(72);
m_introImages->setToolTip(QStringLiteral("配图相对路径列表;使用下方按钮从文件添加"));
introLay->addWidget(new QLabel(QStringLiteral("配图"), m_introContent));
introLay->addWidget(m_introImages);
auto* imgRow = new QHBoxLayout();
m_btnIntroAddImage = new QPushButton(QStringLiteral("添加配图…"), m_introContent);
m_btnIntroRemoveImage = new QPushButton(QStringLiteral("移除选中"), m_introContent);
imgRow->addWidget(m_btnIntroAddImage);
imgRow->addWidget(m_btnIntroRemoveImage);
introLay->addLayout(imgRow);
m_introVideo = new QLineEdit(m_introContent);
m_introVideo->setPlaceholderText(QStringLiteral("可选:视频相对路径(如 assets/entities/xxx.mp4"));
introLay->addWidget(new QLabel(QStringLiteral("视频路径(预留)"), m_introContent));
introLay->addWidget(m_introVideo);
lay->addWidget(m_introHeader);
lay->addWidget(m_introContent);
lay->addStretch(1);
m_introContent->setVisible(false);
m_introSaveTimer = new QTimer(this);
m_introSaveTimer->setSingleShot(true);
connect(m_introSaveTimer, &QTimer::timeout, this, [this]() {
if (!m_introBulkUpdate) {
emit introContentEdited();
}
});
connect(m_introToggle, &QToolButton::clicked, this, [this]() {
setIntroSectionExpanded(!m_introContent->isVisible());
});
connect(m_name, &QLineEdit::editingFinished, this, [this]() {
if (m_name) {
emit displayNameCommitted(m_name->text());
@@ -60,9 +133,41 @@ EntityPropertySection::EntityPropertySection(QWidget* parent)
connect(m_pivot, &Vec2ParamControl::valueChanged, this, &EntityPropertySection::pivotEdited);
connect(m_centroid, &Vec2ParamControl::valueChanged, this, &EntityPropertySection::centroidEdited);
connect(m_userScale, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &EntityPropertySection::userScaleEdited);
connect(m_introTitle, &QLineEdit::textChanged, this, [this](const QString&) { scheduleIntroPersist(); });
connect(m_introBody, &QTextEdit::textChanged, this, [this]() { scheduleIntroPersist(); });
connect(m_introVideo, &QLineEdit::textChanged, this, [this](const QString&) { scheduleIntroPersist(); });
connect(m_btnIntroAddImage, &QPushButton::clicked, this, &EntityPropertySection::introAddImageRequested);
connect(m_btnIntroRemoveImage, &QPushButton::clicked, this, [this]() {
if (!m_introImages || !m_introImages->currentItem()) {
return;
}
delete m_introImages->takeItem(m_introImages->currentRow());
scheduleIntroPersist();
});
}
void EntityPropertySection::setIntroSectionExpanded(bool expanded) {
if (!m_introContent || !m_introToggle) {
return;
}
m_introContent->setVisible(expanded);
m_introToggle->setText(expanded ? QStringLiteral("") : QStringLiteral(""));
}
void EntityPropertySection::scheduleIntroPersist() {
if (m_introBulkUpdate || !m_introSaveTimer) {
return;
}
m_introSaveTimer->start(400);
}
void EntityPropertySection::clearDisconnected() {
if (m_introSaveTimer) {
m_introSaveTimer->stop();
}
m_introBulkUpdate = true;
setEditingEnabled(false);
if (m_name) {
m_name->blockSignals(true);
@@ -78,9 +183,32 @@ void EntityPropertySection::clearDisconnected() {
m_userScale->setValue(1.0);
m_userScale->blockSignals(false);
}
if (m_introTitle) {
m_introTitle->blockSignals(true);
m_introTitle->clear();
m_introTitle->blockSignals(false);
}
if (m_introBody) {
m_introBody->blockSignals(true);
m_introBody->clear();
m_introBody->blockSignals(false);
}
if (m_introVideo) {
m_introVideo->blockSignals(true);
m_introVideo->clear();
m_introVideo->blockSignals(false);
}
if (m_introImages) m_introImages->clear();
setIntroSectionExpanded(false);
m_introBulkUpdate = false;
}
void EntityPropertySection::applyState(const EntityPropertyUiState& s) {
if (m_introSaveTimer) {
m_introSaveTimer->stop();
}
m_introBulkUpdate = true;
setEditingEnabled(true);
if (m_name) {
m_name->blockSignals(true);
@@ -96,6 +224,63 @@ void EntityPropertySection::applyState(const EntityPropertyUiState& s) {
m_userScale->setValue(s.userScale);
m_userScale->blockSignals(false);
}
if (m_introTitle) {
m_introTitle->blockSignals(true);
m_introTitle->setText(s.intro.title);
m_introTitle->blockSignals(false);
}
if (m_introBody) {
m_introBody->blockSignals(true);
m_introBody->setPlainText(s.intro.bodyText);
m_introBody->blockSignals(false);
}
if (m_introVideo) {
m_introVideo->blockSignals(true);
m_introVideo->setText(s.intro.videoPathRelative);
m_introVideo->blockSignals(false);
}
if (m_introImages) {
m_introImages->clear();
for (const QString& p : s.intro.imagePathsRelative) {
if (!p.isEmpty()) {
auto* it = new QListWidgetItem(p, m_introImages);
it->setData(Qt::UserRole, p);
}
}
}
setIntroSectionExpanded(false);
m_introBulkUpdate = false;
}
void EntityPropertySection::appendIntroImagePath(const QString& relativePath) {
if (!m_introImages || relativePath.isEmpty()) {
return;
}
auto* it = new QListWidgetItem(relativePath, m_introImages);
it->setData(Qt::UserRole, relativePath);
scheduleIntroPersist();
}
core::EntityIntroContent EntityPropertySection::introSnapshot() const {
core::EntityIntroContent out;
if (m_introTitle) {
out.title = m_introTitle->text();
}
if (m_introBody) {
out.bodyText = m_introBody->toPlainText();
}
if (m_introVideo) {
out.videoPathRelative = m_introVideo->text().trimmed();
}
if (m_introImages) {
for (int i = 0; i < m_introImages->count(); ++i) {
const QString p = m_introImages->item(i)->data(Qt::UserRole).toString();
if (!p.isEmpty()) {
out.imagePathsRelative.push_back(p);
}
}
}
return out;
}
void EntityPropertySection::setEditingEnabled(bool on) {
@@ -103,6 +288,14 @@ void EntityPropertySection::setEditingEnabled(bool on) {
if (m_pivot) m_pivot->setEnabled(on);
if (m_centroid) m_centroid->setEnabled(on);
if (m_userScale) m_userScale->setEnabled(on);
if (m_introHeader) m_introHeader->setEnabled(on);
if (m_introToggle) m_introToggle->setEnabled(on);
if (m_introTitle) m_introTitle->setEnabled(on);
if (m_introBody) m_introBody->setEnabled(on);
if (m_introVideo) m_introVideo->setEnabled(on);
if (m_introImages) m_introImages->setEnabled(on);
if (m_btnIntroAddImage) m_btnIntroAddImage->setEnabled(on);
if (m_btnIntroRemoveImage) m_btnIntroRemoveImage->setEnabled(on);
}
} // namespace gui