增加预览页介绍信息显示
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/domain/EntityIntro.h"
|
||||
#include "props/PropertySectionWidget.h"
|
||||
|
||||
#include <QPointF>
|
||||
@@ -8,6 +9,12 @@
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QDoubleSpinBox;
|
||||
class QTextEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
class QToolButton;
|
||||
class QTimer;
|
||||
class QWidget;
|
||||
|
||||
namespace gui {
|
||||
class Vec2ParamControl;
|
||||
@@ -22,6 +29,7 @@ struct EntityPropertyUiState {
|
||||
QPointF pivot;
|
||||
QPointF centroid;
|
||||
double userScale = 1.0;
|
||||
core::EntityIntroContent intro;
|
||||
};
|
||||
|
||||
// 实体相关属性(可嵌入 QStackedWidget 的一页)
|
||||
@@ -33,20 +41,41 @@ public:
|
||||
void clearDisconnected();
|
||||
void applyState(const EntityPropertyUiState& s);
|
||||
void setEditingEnabled(bool on);
|
||||
[[nodiscard]] core::EntityIntroContent introSnapshot() const;
|
||||
void appendIntroImagePath(const QString& relativePath);
|
||||
|
||||
signals:
|
||||
void displayNameCommitted(const QString& text);
|
||||
void pivotEdited(double x, double y);
|
||||
void centroidEdited(double x, double y);
|
||||
void userScaleEdited(double value);
|
||||
/// 介绍字段变更后防抖触发,由主窗口写入工程
|
||||
void introContentEdited();
|
||||
void introAddImageRequested();
|
||||
|
||||
private:
|
||||
void scheduleIntroPersist();
|
||||
void setIntroSectionExpanded(bool expanded);
|
||||
|
||||
QLineEdit* m_name = nullptr;
|
||||
QLabel* m_depth = nullptr;
|
||||
QLabel* m_distScale = nullptr;
|
||||
Vec2ParamControl* m_pivot = nullptr;
|
||||
Vec2ParamControl* m_centroid = nullptr;
|
||||
QDoubleSpinBox* m_userScale = nullptr;
|
||||
|
||||
QLineEdit* m_introTitle = nullptr;
|
||||
QTextEdit* m_introBody = nullptr;
|
||||
QLineEdit* m_introVideo = nullptr;
|
||||
QListWidget* m_introImages = nullptr;
|
||||
QPushButton* m_btnIntroAddImage = nullptr;
|
||||
QPushButton* m_btnIntroRemoveImage = nullptr;
|
||||
|
||||
QWidget* m_introHeader = nullptr;
|
||||
QToolButton* m_introToggle = nullptr;
|
||||
QWidget* m_introContent = nullptr;
|
||||
QTimer* m_introSaveTimer = nullptr;
|
||||
bool m_introBulkUpdate = false;
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
|
||||
Reference in New Issue
Block a user