/
klischa
/
AstraScanner2
Обзор
Документация
Войти
/
klischa
/
AstraScanner2
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/gui/HelpDialog.cpp
200 строк
7 KB
Arena Agent
ui: add contextual help for quality coverage summary
19 июн 2026, 15:25
19 июн 2026, 15:25
942953a
Код
Авторство
О чём код?
#include "HelpDialog.h" #include <QDialogButtonBox> #include <QFileInfo> #include <QHBoxLayout> #include <QListWidget> #include <QPushButton> #include <QSplitter> #include <QTextBrowser> #include <QVBoxLayout> #include <QCoreApplication> #include <QDir> #include <QUrl> #include <iterator> namespace { QString fallbackHelpHtml() { return QStringLiteral(R"( <html><body style='font-family:Segoe UI, Arial, sans-serif; line-height:1.5;'> <h1>Справка по работе со сканером</h1> <p>Файл встроенной справки не найден. Убедитесь, что рядом с приложением присутствует каталог <code>help/</code>.</p> <p>Базовый сценарий:</p> <ol> <li>Создайте или откройте проект.</li> <li>Проверьте камеру и выполните калибровку.</li> <li>Перейдите на вкладку «Сканирование», выберите режим трекинга и начните Preview/Scan.</li> <li>После захвата перейдите на вкладку «Обработка» для очистки облака, ICP-мержа и Poisson-реконструкции.</li> </ol> </body></html> )"); } QString resolveHelpPath() { const QString appDir = QCoreApplication::applicationDirPath(); const QString currentDir = QDir::currentPath(); const QStringList candidates = { QDir(appDir).filePath("help/SCANNER_USER_GUIDE.html"), QDir(currentDir).filePath("help/SCANNER_USER_GUIDE.html"), QDir(appDir).filePath("../help/SCANNER_USER_GUIDE.html"), QDir(currentDir).filePath("../help/SCANNER_USER_GUIDE.html"), QDir(appDir).filePath("../../help/SCANNER_USER_GUIDE.html"), QDir(currentDir).filePath("../../help/SCANNER_USER_GUIDE.html") }; for (const QString &candidate : candidates) { if (QFileInfo::exists(candidate)) { return QFileInfo(candidate).absoluteFilePath(); } } return QString(); } } // namespace HelpDialog::HelpDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(QStringLiteral("Справка по работе со сканером")); setModal(false); resize(1180, 820); buildUi(); loadHelpContent(); } void HelpDialog::buildUi() { auto *outer = new QVBoxLayout(this); auto *splitter = new QSplitter(this); splitter->setChildrenCollapsible(false); m_sectionsList = new QListWidget(this); m_sectionsList->setMinimumWidth(250); m_sectionsList->addItem(QStringLiteral("Быстрый старт")); m_sectionsList->addItem(QStringLiteral("Проект и подготовка")); m_sectionsList->addItem(QStringLiteral("Главная вкладка")); m_sectionsList->addItem(QStringLiteral("Калибровка")); m_sectionsList->addItem(QStringLiteral("Сканирование")); m_sectionsList->addItem(QStringLiteral("Режимы трекинга")); m_sectionsList->addItem(QStringLiteral("Обработка")); m_sectionsList->addItem(QStringLiteral("Настройки")); m_sectionsList->addItem(QStringLiteral("Neural + ICP confirm")); m_sectionsList->addItem(QStringLiteral("Рецепты работы")); m_sectionsList->addItem(QStringLiteral("Типовые проблемы")); m_textBrowser = new QTextBrowser(this); m_textBrowser->setOpenExternalLinks(true); m_textBrowser->setOpenLinks(true); splitter->addWidget(m_sectionsList); splitter->addWidget(m_textBrowser); splitter->setStretchFactor(0, 0); splitter->setStretchFactor(1, 1); splitter->setSizes({280, 860}); outer->addWidget(splitter, 1); auto *buttons = new QDialogButtonBox(QDialogButtonBox::Close, this); m_closeBtn = buttons->button(QDialogButtonBox::Close); connect(m_closeBtn, &QPushButton::clicked, this, &QDialog::close); outer->addWidget(buttons); connect(m_sectionsList, &QListWidget::currentRowChanged, this, [this](int row) { static const char *anchors[] = { "quickstart", "project-prep", "home-tab", "calibration", "scan-tab", "tracking-modes", "processing", "settings", "neural-icp", "recipes", "troubleshooting" }; if (row >= 0 && row < static_cast<int>(std::size(anchors))) { m_textBrowser->scrollToAnchor(QString::fromUtf8(anchors[row])); } }); } void HelpDialog::openSection(const QString &anchor) { if (anchor.isEmpty()) { if (m_sectionsList->count() > 0) { m_sectionsList->setCurrentRow(0); } return; } selectSectionByAnchor(anchor); m_textBrowser->scrollToAnchor(anchor); } void HelpDialog::selectSectionByAnchor(const QString &anchor) { if (!m_sectionsList) { return; } struct AnchorToRow { const char *anchor; int row; }; static const AnchorToRow mapping[] = { {"quickstart", 0}, {"project-prep", 1}, {"home-tab", 2}, {"calibration", 3}, {"scan-tab", 4}, {"tracking-modes", 5}, {"processing", 6}, {"settings", 7}, {"neural-icp", 8}, {"recipes", 9}, {"troubleshooting", 10}, {"turntable-mode", 4}, {"quality-mode", 4}, {"cloud-cleanup", 6}, {"object-prep", 6}, {"icp-merge", 6}, {"poisson", 6}, {"mesh-post", 6}, {"icp-settings", 7}, {"poisson-settings", 7}, {"voxel-leaf-size", 7}, {"frame-skip", 7}, {"icp-max-correspondence", 7}, {"poisson-depth", 7}, {"poisson-point-weight", 7}, {"poisson-normal-radius", 7}, {"neural-icp-fitness", 8}, {"neural-icp-correction-translation", 8}, {"neural-icp-correction-rotation", 8} }; for (const auto &entry : mapping) { if (anchor == QLatin1String(entry.anchor)) { m_sectionsList->setCurrentRow(entry.row); return; } } } void HelpDialog::loadHelpContent() { const QString helpPath = resolveHelpPath(); if (helpPath.isEmpty()) { m_textBrowser->setHtml(fallbackHelpHtml()); if (m_sectionsList->count() > 0) m_sectionsList->setCurrentRow(0); return; } m_textBrowser->setSource(QUrl::fromLocalFile(helpPath)); if (m_sectionsList->count() > 0) m_sectionsList->setCurrentRow(0); }