#include "dialogs/EntityIntroPopup.h" #include #include #include #include #include #include #include #include #include #include #include namespace gui { namespace { constexpr int kMaxThumb = 200; QString elideLine(const QString& s, int maxChars) { if (s.size() <= maxChars) { return s; } return s.left(maxChars - 1) + QChar(0x2026); } } // namespace EntityIntroPopup::EntityIntroPopup(QWidget* parent) : QWidget(parent) { setAttribute(Qt::WA_TranslucentBackground, false); setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); auto* root = new QVBoxLayout(this); root->setContentsMargins(14, 12, 14, 12); root->setSpacing(8); m_title = new QLabel(this); QFont tf = m_title->font(); tf.setBold(true); tf.setPointSizeF(tf.pointSizeF() + 1.5); m_title->setFont(tf); m_title->setWordWrap(true); root->addWidget(m_title); m_body = new QTextEdit(this); m_body->setReadOnly(true); m_body->setFrameShape(QFrame::NoFrame); m_body->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_body->setMaximumHeight(180); m_body->setPlaceholderText(QStringLiteral("(无)")); root->addWidget(m_body); m_imagesHost = new QWidget(this); m_imagesLayout = new QVBoxLayout(m_imagesHost); m_imagesLayout->setContentsMargins(0, 0, 0, 0); m_imagesLayout->setSpacing(6); root->addWidget(m_imagesHost); m_videoHint = new QLabel(this); m_videoHint->setWordWrap(true); m_videoHint->setStyleSheet(QStringLiteral("QLabel { color: palette(mid); font-size: 11px; }")); root->addWidget(m_videoHint); setMinimumWidth(280); setMaximumWidth(420); hide(); } void EntityIntroPopup::setProjectDir(const QString& absoluteProjectDir) { m_projectDirAbs = absoluteProjectDir; } void EntityIntroPopup::setContent(const core::EntityIntroContent& content) { const QString t = content.title.trimmed().isEmpty() ? QStringLiteral("介绍") : content.title.trimmed(); m_title->setText(elideLine(t, 200)); m_body->setPlainText(content.bodyText); while (QLayoutItem* it = m_imagesLayout->takeAt(0)) { if (QWidget* w = it->widget()) { w->deleteLater(); } delete it; } for (const QString& rel : content.imagePathsRelative) { if (rel.isEmpty()) { continue; } const QString abs = m_projectDirAbs.isEmpty() ? QString() : QDir(m_projectDirAbs).filePath(rel); auto* lab = new QLabel(m_imagesHost); lab->setAlignment(Qt::AlignCenter); if (!abs.isEmpty() && QFileInfo::exists(abs)) { QPixmap pm(abs); if (!pm.isNull()) { if (pm.width() > kMaxThumb || pm.height() > kMaxThumb) { pm = pm.scaled(kMaxThumb, kMaxThumb, Qt::KeepAspectRatio, Qt::SmoothTransformation); } lab->setPixmap(pm); } else { lab->setText(QStringLiteral("(无法加载图片)")); } } else { lab->setText(QStringLiteral("(缺少文件:%1)").arg(rel)); } lab->setWordWrap(true); m_imagesLayout->addWidget(lab); } if (content.videoPathRelative.trimmed().isEmpty()) { m_videoHint->setText(QStringLiteral("视频介绍")); } else { m_videoHint->setText(QStringLiteral("播放功能预留").arg(content.videoPathRelative)); } adjustSize(); } void EntityIntroPopup::showNearCanvasPoint(const QPoint& viewPos, QWidget* canvasWidget) { if (!canvasWidget) { return; } adjustSize(); const QPoint globalAnchor = canvasWidget->mapToGlobal(viewPos); QScreen* scr = QGuiApplication::screenAt(globalAnchor); if (!scr) { scr = canvasWidget->screen(); } const QRect screen = scr ? scr->availableGeometry() : QRect(0, 0, 1920, 1080); int x = globalAnchor.x() + 18; int y = globalAnchor.y() - height() / 3; if (x + width() > screen.right()) { x = globalAnchor.x() - width() - 18; } if (x < screen.left()) { x = screen.left() + 8; } if (y + height() > screen.bottom()) { y = screen.bottom() - height() - 8; } if (y < screen.top()) { y = screen.top() + 8; } move(x, y); show(); raise(); } void EntityIntroPopup::clearAndHide() { hide(); m_title->clear(); m_body->clear(); while (QLayoutItem* it = m_imagesLayout->takeAt(0)) { if (QWidget* w = it->widget()) { w->deleteLater(); } delete it; } m_videoHint->clear(); } void EntityIntroPopup::paintEvent(QPaintEvent* e) { Q_UNUSED(e); QPainter p(this); p.setRenderHint(QPainter::Antialiasing, true); const QRect r = rect().adjusted(1, 1, -1, -1); p.fillRect(r, palette().base()); p.setPen(QPen(palette().mid().color(), 1)); p.drawRoundedRect(r, 8, 8); } } // namespace gui